Extending Emscripten to Support Objective-C — running iOS Apps on the Web
In this post, we’ll give an overview of the modifications that were needed to support Objective-C on Emscripten.
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
If that sounds too good to be true, well, you’d be right. Naturally, additional modifications are needed.
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.
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.
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.
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.
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.
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.
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.