Highly experimental LLVM IR → ASM.JS compiler
Rooibos converts LLVM bitcode (most commonly produced with clang -c -emit-llvm ...
) into ASM.JS code¹. In theory, this means that any language that has an LLVM-compatible frontend (including C and dialects, thanks to Clang) can be used to write a web app frontend. (In practice, there's the small question of porting runtime libraries, but that's another matter.)
¹ Technically, Rooibos generates a SpiderMonkey-compatible JSON representation of the AST for ASM.JS-compliant code. You'll need another tool to actually generate the JavaScript; see below.
Roobius has some dependencies that you'll need to wire up before you can compile it.
- Make sure you have Tup and npm installed.
- Clone this repository into some directory
$ROOT
. mkdir $ROOT/tools; cd $ROOT/tools
- Somewhere, probably out of the Rooibos directory, build LLVM using the instructions here. Link these LLVM directories into your new
tools
directory so Rooibos can find them: ln -s where-you-want-to-build-llvm/bin ./bin
— built binariesln -s where-you-want-to-build-llvm/lib ./lib
— built librariesln -s where-you-want-to-build-llvm/include ./include-build
— build-specific headersln -s where-you-want-llvm-to-live/include ./include-src
— build-independent headers- Clone Niels Lohmann's JSON library:
cd $ROOT/tools; git clone https://github.com/nlohmann/json.git
- Install escodegen and UglifyJS:
cd $ROOT/tools; npm install escodegen ugilfy-js
- Pick a variant:
tup variant configs/{default,release}.conf
default
includes debug symbols and produces some extra test output files (human-readable.ll
and minified JS) to aid developmentrelease
runs optimization passes on Rooibos itself and skips the extra test output
- Run Tup:
cd $ROOT; tup
If all dependencies are in place, this will build Rooibos and run the integration tests by running Rooibos against the C files in tests
and diff
ing against their expected results. If Tup comes back green and Updated
, you're good to go.
Rooibos picks up from LLVM bitcode (.bc
files). There's a working example in tests/Tupfile
, but the gist of it is:
$ generate foo.bc
$ $BUILD/rooibos/rooibos-codegen < foo.bc > foo.ast
$ $TOOLS/node_modules/.bin/esgenerate foo.ast > foo.js
If you're starting from C(++) sources, the command you want is clang -c -emit-llvm -o foo.bc foo.c
.
(For curiosity's sake, the Tupfile also minifies the resulting JavaScript into a separate .min.js
file if you're building the default
variant.)
The produced ASM.JS function is itself wrapped in a non-ASM.JS adaptor, which is responsible for setting up the heap, bridging native JavaScript and ASM.JS types, and so on. Currently, all functions defined in the IR are exposed through the adaptor which is attached to the global variable (window
in browsers) under the name ASM
. For instance, a source file
int echo(int value)
{
return value;
}
can be used like this:
console.log(ASM.echo(42));
Rooibos is meant to be not overly verbose in its output, partially inspired by C++'s "don't pay for what you don't use" philosophy. If no source code references the heap, for instance, then the runtime won't contain the code to set up the heap in the first place. As another example, branch instructions are implemented by emulating a program counter with a local PC
variable and a switch
nested in a while (1)
loop. Functions with only one basic block don't need to emulate the program counter, so they don't.
- IR support
- Functions
- Global variables
- Parameters
- Return values
- Calls to other ASM functions
- Calls to the ASM.JS
stdlib
- Calls to the ASM.JS foreign function interface
- Heap access
-
asm
support - All other IR instructions (see
README.instructions.md
)
- Type support
- Integers
- Floats
- Doubles
- Dependency system integrations
- Direct global assignment (
window.ASM = ...
) - CommonJS (
require([], function() { ... })
) - Browserify (
module.exports = ...
)
- Direct global assignment (
- JS integrations
- Manipulating JS objects from ASM.JS code (via FFI)
- Converting JS strings to
const char *
s and vice-versa
- Tool support
- Rooibos driver
- Source maps
- C headers for browser environment
- C++ runtime(?)