Playing with WebAssembly to run snippets of code
Tags: osd600, webassembly
Published: 2022-01-11 20:57:09

I would like to talk about my experience with the project that I decided to embark on a month ago or so.

As per my [last post](https://dev.to/jerryhue/planning-an-online-c-compiler-for-ipc144-a6o), I wanted to implement a feature that would make the C code examples interactive: that meant that you could not only run them by clicking a button, but also modify them and then run with the new changes.

While I was trying out several ideas on my computer, I learned that this feature was going to be more involved that I thought it would be.

Of course, I decided to settle on something simpler while I put the actual feature for later.

## Some discoveries

The first thing I realized when trying this seemingly small feature is how involved it actually was.

In a normal set up, you would have a front-end and a back-end. Essentially, you would want the back-end to handle the compilation of the snippets. This would let you implement the editable part of the feature. If you wanted to be a little bit more daring, you could also run the program in the back-end and send the output as a response.

While this set-up is not necessarily easy to do (you have to be careful to set up a well-contained environment for security), it is a much simpler alternative than what I had as an option.

As per my previous post, I essentially described a WebAssembly program that produces WebAssembly programs depending on some C source code, essentially, a C-to-WASM compiler.

Now, to find a C-to-WASM compiler is not that hard. The most well-known example is clang, which uses LLVM as a backend to generate WebAssembly. Combined with Emscripten, you get not only the WASM code, but also JavaScript glue code, as well. 

The major problem is that WASM is a more limited VM, compared to what is possible in a normal computer environment.

### First discovery: I/O is a real pain now

The first major setback was I/O and its support in WebAssembly.

You see, WebAssembly is just a VM that runs in the browser, just like the JavaScript runtime or the Java Virtual Machine. None of these "machines" have the concept of I/O directly integrated with them, just like normal CPU's do. A CPU does not know what a file is, it just handles everything into its lowest levels.

Thus, the one that has to provide the concept of I/O, such as the file system and such, is Emscripten. Emscripten does a good job on adapting everything in the source code so that it can be used in the browser seamlessly, but there are still some limitations. For example, Emscripten needs to create a virtual file system if it wants to support things like `fopen` and `fclose`. With `printf` and `scanf`, it will try to offer some defaults that do not include a file system.

This is fine, but that does not mean that it is perfect for my purposes. Since a compiler like clang actually does a lot of I/O, having a file system like the one Emscripten supports might not be enough for the compiler to actually work.

### Second discovery: Porting is not that easy

However, just because Emscripten does not support a general file system for all purpose does not mean that it is impossible to use clang in the web. You could go through the entire source code of the clang compiler and somehow port it so that it works just fine in WASM.

It is easier said than done.

If you ever had to go through a huge codebase to make a small change, then imagine having to do that throughout the whole codebase. Of course, you would need in depth knowledge of the inner workings of the compiler. If you don't have it, then you would need to constantly ask the maintainers about the codebase, as if the maintainers don't have a enough work already...

This also means that you would have to port LLVM. Remember, clang depends on LLVM, and there are also other minor dependencies which I won't mention because I don't know them all.

When I discovered all that work, I started to realise how screwed I was.

## Smaller expectations

Well, live code examples are a failed project. Now what?

Well, first, I decided to set up the actual solution for later, when I have more patience to go through all of that, so that I can make a smaller demo. I might think of another solution that is more realizable.

Then, I went on and tried to make the examples runnable.

It actually went better than expected. There were still some limitations (I couldn't make `scanf` to actually work, and the whole file reading part was also not fully realized), but I learned the at least one part of the feature was not unnecessarily hard.

You can check the PR [here](https://github.com/Seneca-ICTOER/Intro2C/pull/171).