2.5 KiB
BeamJs
BeamJs is an effort to export BEAM byte code to JavaScript and execute it. Currently, it is in a VERY incomplete state -- only some op codes are exportable, and the JS runtime has not been written.
Why?
There have been other efforts to cross-compile Elixir code so that it can be run in JS engines and browsers:
- Firefly attempted to create an alternate toolchain for Elixir based on WASM, but the project is archived.
- Popcorn cross-compiles the entire AtomVM + stdlib + application code to WASM.
- Hologram takes an alternate approach, transforming an Elixir AST to a JS format and running it through a JS runtime.
I had an idea. What if we split the difference? What if used the BEAM byte code that the compiler already generates, but we run it through an emulator written in JS. This has certain advantages:
- The number of opcodes is relatively small-- ~160. This means that our emulator code can be relatively small also.
- Each instruction is relatively simple-- moving values from one register to another, doing simple comparisons, jumping execution from one label to another, etc. That makes each operation easy to implement and easy to test.
- We can simulate concurrent processes even in the single-threaded JS environment. Each individual BEAM instruction executes in a finite amount of time, and the scheduler can simply execute N instructions before switching processes and running N instructions there.
- This model allows us to learn about how the BEAM works in an interactive way. Imagine using a web app to simulate the BEAM in a browser and being able to pause processes to see the current state of the registers, stack, heap, etc.
However, this approach has at least one big disadvantage. I'm not sure this approach will ever be "fast", especially compared to the BEAM or AtomVM running natively on hardware. These runtimes are written in low-level languages and use direct memory access and JIT to execute code quite quickly. BeamJs is several abstractions higher-level than that. Since I'm doing this mostly as a way to learn and teach the BEAM, that's an acceptable trade-off for my use case.
Installation
If available in Hex, the package can be installed
by adding beam_js to your list of dependencies in mix.exs:
def deps do
[
{:beam_js, "~> 0.1.0"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/beam_js.