Apple recommends that new apps be compiled to bitcode. But what is bitcode, exactly, and what are its advantages and disadvantages?

The final release of Xcode 7 a few weeks ago introduced a new setting, "Enable Bitcode", which is set to "Yes" by default. We updated our iOS SDK to version 4.1.0 around the same time, but alas, it does not support bitcode. For the moment, the SDK can only be used in iOS apps with bitcode disabled.

Knowing that couldn't last, we dug into bitcode to figure out what it is, why Apple recommends it, and how we could most easily support it in the next release of the iOS SDK.

What is Bitcode?

Bitcode is the intermediate representation (IR) generated by the LLVM Compiler to represent code parsed from a human-readable programming language and ready to be compiled into machine code. This is an important part of the design of LLVM, which maintains a sharp distinction between frontends, which parse various programming languages, andbackends, which write machine code for various processor architectures. Parsing frontend code into bitcode allows LLVM to decouple and mediate the relationship between languages and processor architectures.

In theory, Apple can release new processors and simply recompile bitcode-encoded App Store apps without any work from developers. In practice, this is unlikely to happen, because many frontend languages often do encode expectations about particular backends. Bitcode can't properly mediate such expectations, of course. It's likely that recompiling bitcoded-encoded apps could be used to automate recompilation to take advantage of more modest changes. Think new processor instructions or compiler optimizations rather than new processor architectures. See this comprehensive Quora answer for more detail.

How is Bitcode Different from Bytecode?

The simplest way to think about it is that bytecode is a compiled binary designed to execute on a software interpreter, such as the JVM or Microsoft's CLR. Bitcode, on the other hand, is not designed for execution. Rather, it's an abstract encoding of structured data, similar to XML, designed to be compiled into executable code. In other words, bitcode is truly an intermediate representation, whereas bytecode is typically the final output of compilation.

More technically, the reason it's called "bitcode" instead of "bytecode", according to LLVM creator Chris Lattner is that, at a low level:

The format is literally a bitstream, not a bytestream. See this document for more details.

Should You Use Bitcode?

The current release of the iovation Mobile SDK for iOS, v4.1.0, does not include bitcode support, so any iOS apps that use it must disable bitcode. watchOs and tvOS targets, however, require bitcode. So if your app includes Apple Watch or TV targets, disable bitcode in your app targets but leave it enabled in your Watch and TV targets.

The same principals apply to any other third-party libraries in your app. Until they're all updated to support bitcode, the app cannot be submitted as bitcode. We expect the next release of the SDK to include bitcode support (we're testing it now, aiming for release in the near future).

Once all libraries you use have been updated, the question becomes more complicated.

You'll need to consider the tradeoffs. Releasing bitcode-encoded apps on the App Store will simplify the upgrade process when Apple releases new hardware or adds new optimizations to the LLVM compiler. More immediately, it also allows your apps to take up less storage on devices. Since Apple is doing all the compiling, they will create separate binaries for each supported architecture (armv7, arm64, etc.), so that users no longer have to download a "fat binary" with the machine code for all supported architectures. This is the core of Apple's App Thinning feature.

However, since Apple will be compiling apps on your behalf, it also means that your users will be using binaries that you never directly tested yourself. In practice this may not be a big deal; after all, Apple is using the same compiler as you. But it may be a newer version, with its own idiosyncrasies, and will leave no way for you to test it directly. There's some fear among developers that the variance between binaries you've tested and binaries generated by Apple could introduce user-visible bugs that cannot be replicated or fixed by developers. In other words, the binaries your users install from the App Store are different from the binaries you've built and tested on devices yourself.

More worrisome is the potential for exploits. In "Bitcode Demystified", developer Alex Denisov points out that, if a malefactor is able to access your bitcode, they can more easily determine how it works and introduce exploits. This is especially worrisome for third party libraries, such as the iovation SDK, which are not distributed directly via the App Store.

But if the App Store compiler infrastructure itself were to be exploited, it could be even worse. As security researcher Frederic Jacobs explains in "Why I’m not enabling Bitcode":

The centralization of the building and signing process is what worries me: an adversary could find a vulnerability in the LLVM backend to obtain remote code execution on Apple’s Bitcode compilation infrastructure to inject a compiler trojan that would affect every single app on the App Store that was submitted with Bitcode.

That could be disastrous for your app, for users, and for Apple. We can only rely on Apple to take every measure to prevent this from happening, but since there's no such thing as a completely secure infrastructure, and we're talking about a potential single point of exploit, it's definitely a point of concern.

Conclusion

Our recommendation is to take a wait and see approach to the adoption of bitcode. In the short term, it's impossible until all of your third-party libraries add support for bitcode. But even once that's done, it's an open question whether the benefits outweigh the debugging and security uncertainties inherent in the use of bitcode. Unless Apple starts requiring bitcode for all apps, we recommend holding back for 6-12 months and waiting to see how things shake out.