Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
LLVM Backend #2264
This lets us Prepack to native machine code or WebAssembly - without a JS runtime.
Prepack knows a lot about a program that it can evaluate. It is also highly specialized at getting rid of intermediate objects.
Most of the complexity of the serializer has to do with residual objects and closures that might leak to other JS.
Most of the complexity of a JS runtime comes from supporting the object model.
If we forbid leaking objects, and that Prepack has full knowledge of the program, then we know a lot about the types. This won't work with existing programs but new programs written for these constraints could benefit from this.
I wrote a new backend in parallel to the normal serializer. There is not a lot in common with the problem space so I decided to add a new serializer rather than build on the existing one.
In this first PR, only booleans and numbers are supported at the interop layer but I expect to support closures, symbols, and array buffers. Longer term we can support strings and Typed Objects.
The type system is currently strongly typed so it will reject a program where abstract values yield more than one type.
Functions are modeled by the normal function with return
I model booleans as
The limitations are mainly in the same set of problems we're currently investigating. Loops and recursive functions are not allowed.
The generated code must inline everything to completely get rid of all objects. This can yield bloated and suboptimal code.
In the future I hope that we can use arena allocation of custom object structures to temporarily store values created in recursive functions and loops.
Is This Useful?
I could see this as helpful for simpler functions such as animation functions that need to run on a different thread, audio processing functions, simple but highly parallizable functions like shaders etc.
It could potentially be useful for some React components that needs to execute at extreme performance.
This PR adds an optional dependency on the
Downstream users of
It requires both cmake and LLVM to be installed.
MacOS installation instructions:
Additionally running the
Building a Native Program
Compile to LLVM bitcode:
Compile to native assembly:
Link the program to a native executable:
Debug by printing the LLVM IR assembly language code:
Basically the idea is that the main function and any residual function are “actors” that process some data. They’ll use arena allocation and are expected to be short lived.
A runtime outside of these can control the memory management of long lived objects. That allows for parallelism and more efficient memory management outside of these “worklets”.
You bypass the existing serializer, but then still find the existing
Also, I wonder if you'd soon need something like the
Yea, this exercise really shows where our abstractions leak and where they don't. The generators are fairly flexible but still a bit leaky. There are some things in there that isn't really necessary from interpreters point of view, but it's a hard dependency from the interpreter.
E.g. creating intermediate variables happens in the interpreter right now. The generator also inserts temporary variables itself. The rest of the system is essentially SSA so it gets a little awkward to manage both. In this PR I just undo this by storing my own variable map and undoing the temporary assignment. We should try to move that concept out to be completely isolated in the serialization pass instead of interleaved.
I originally expected LLVM to help me with much of what the visitor does, but it is lacking in some areas so yea I might need a pre-processing pass like the ResidualHeapVisitor.
And as a plus, the
Ideally, I'd like to move out all build nodes to a Babel-specific place, and instead place specific named instructions in the generator. That would allow printing the generator tree in some nice assembly format, and then different backends can be plugged in more easily.