Extending Emscripten to Support Objective-C — running iOS Apps on the Web

Fumiya Chiba
Tombo Blog
Published in
3 min readFeb 14, 2017

Emscripten is a source-to-source compiler that converts C/C++ to JavaScript. As part of our effort to run iOS applications on web browsers, we have extended Emscripten to compile and run Objective-C.

In this post, we’ll give an overview of the modifications that were needed to support Objective-C on Emscripten.

Inside Objective-C

First, let’s look at how Objective-C works internally.

Let’s consider an Objective-C message call like below.

id foo = [dic objectForKey:bar];

Internally, this is translated into a function call like below.

id foo = objc_msgSend(dic, @selector(objectForKey:), bar);

Likewise, metadata such as class declarations are converted to C structures and C function pointer tables. There are held in memory just like global variables. objc_msgSend reads this information, finds the appropriate function from the class inheritance tree, and calls it.

This mechanism is comprised of several components.

First, the conversion from Objective-C to C is implemented in the compiler, clang. Meanwhile, functions such as objc_msgSend are implemented in the runtime library and are dynamically linked at runtime. There are several different runtime libraries, and each library has different conversion requirements (thus clang has several different implementations of the Objective-C to C conversion). Finally, implementations for basic objects such as NSObject and NSString are included in the Foundation framework separate from runtime.

Changes to clang

Emscripten uses clang to convert C/C++ to JavaScript, via LLVM-IR. Therefore, once we extend Emscripten so it can call the currently unsupported clang features needed for Objective-C, much of the work will be complete!

If that sounds too good to be true, well, you’d be right. Naturally, additional modifications are needed.

Metadata

For example, Objective-C stores its class metadata in the DATA segment of executable and library files. But Emscripten doesn’t have the concept of segments! So we created a process that gathers all the Objective-C metadata into one ‘special data location’.

Variable Length Arguments

The objc_msgSend family of functions take variable length arguments in Objective-C, but Emscripten will not let us use function pointers unless we know the signature of the called function. We convert these to functions with fixed length arguments, such as void objc_msgSend_vii(int,int).

Changes to the Runtime library

As mentioned earlier, Objective-C has multiple runtimes. They are all open source. This time we decided to use Apple’s runtime, objc4, as our starting point.

Linking

objc4 uses hooks at dynamic link loading to begin operations. While Emscripten does support dynamic linking, its capabilities are limited. Thus, we modified objc4 to work with static linking.

Metadata

As mentioned earlier, we made changes to clang to store metadata in a ‘special data location’ instead of Objective-C’s DATA segment. Accordingly, we modified the objc4 runtime to read the ‘special data’ output from clang.

Environment Dependencies

There is a big list of environment dependent parts like #ifdef TARGET_OS_MAC that we rewrote. Luckily for us, objc4 is highly portable and even runs on Windows!

Changes to Foundation framework

The Foundation framework consists of CoreFoundation (implemented in C) and Foundation, which can (in a narrow sense) be thought of as an Objective-C wrapper around CoreFoundation.

Environment Dependencies

Like obj4, CoreFoundation also has environment dependencies, such as input/output and directory structures. We made modifications so that these would work on Emscripten.

CoreFoundation is open sourced by Apple and Foundation is open sourced by Apportable, so we were able to build on top of their work.

Conclusion

This post gave a big picture overview of the modifications we made to compile and run Objective-C on Emscripten.

We’ve opted to discuss our general approach and category of modifications rather than the implementation details, since on a granular level, the work has been closer to a very very long list of bug fixes rather than novel architectural breakthroughs. But the work continues to be worthwhile, as we continue to develop technologies for the Open Web.

To run iOS applications on a browser, further work downstream is required. We’ll be sharing that work in future blog posts.

A big thanks to all the open source contributors whose work we have been able to leverage, especially Mozilla and Emscripten. We have made some modest contributions to these projects so far, and hope to give back much more in the future.

Demo

We’ve been working with game companies to convert their iOS games to Web games. You can try some of them out on our demo site.

(Feedback Welcome!)

Enjoy!

--

--