Run C From JavaScript |
Written by Mike James |
Wednesday, 25 September 2024 |
The serverside JavaScript engine Bun has a new trick. You supply it a C file and it will let you call C functions from JavaScript. Genius or insane? C is the language we all turn to when speed is of the essence. A good optimizing compiler can generate machine code from a C program that is as good as even a reasonably experienced assembly language programmer can create. As a result there is a general requirement to be able to call a C function from whatever language you are using and there are many C libraries that do important things as efficiently as it is possible to do them. So-called Foreign Function Interfaces or FFIs are common, but not so much in JavaScript because of the need to run it in a browser. If JavaScript can run C code then it can escape the browser sandbox and access any part of the system. A few years back Google added the ability to run C/C++ in Chrome using NaCl Native Client. This was great for developers, but terrible for security and it was dropped in 2017 as WebAssembly was promised to provide an alternative. The idea was that WebAssembly was a lower-level language that could run alongside JavaScript, which was fast, and would provide the same security by running in the same sandbox. How does this help with running C code? Easy, you simply compile the C code to WebAssembly and use it in place of the real C library. The problem is that this is extra work and it isn't particularly stable. For the browser-based JavaScript engine this is really the only option, but for a server-based engine such as Node or Bun there is an alternative. The V8 JavaScript engine, the one used in Chrome, has an N-API (Native API) which allows C functions to be called. There are a number of problems with using napi, but the main objection seems to be that it is slow and cumbersome. Now, Jarred Sumner, working on Bun, has come up with a better idea. Extend some JavaScript syntax to allow it to call a C compiler, which is then used to compile a C function and generate wrappers for data exchange. For example, if you have a C function that prints "hello world" you could call it from JavaScript using: import { cc } from "bun:ffi"; export const { hello(); This compiles the C code in hello.c and provides information on its parameters and return type. Once compiled, the function can be called as if it was a JavaScript function. At the core of this magic is a piece of software that I haven't seen in many a year - TinyCC. This amazing little early compiler for C was the bedrock of development before the optimizing compilers like GCC came along. TinyCC is a very fast compiler that the JavaScript engine uses to compile the C to machine code. A simple function compiles in milliseconds. After the C is compiled, it is claimed that it is fast to call with an overhead on a C to C call of just 2ns at 6ns. The C code runs in the same memory space as the JavaScript engine and so should be reasonably secure - especially so since it is only loading code from a safe, we hope, local source. Even so, I think C is sufficiently capable to find ways to do naughty things, given the opportunity. I can see it being useful if you have a few interface functions to a bigger implementation, but I don't think recompiling a large set of functions every time they are needed is going to be a good way to work. Fundamentally, the problem is providing a good way for JavaScript to work with pre-compiled C code and this doesn't hack it. It is surprising how things go round though -- TinyCC I never thought I'd see the like again.
More InformationCompile and run C in JavaScript Related ArticlesNative Code On Chrome Dropped In Favour Of WebAssembly Wasmer JS SDK - WebAssembly In The Browser Run WebAssembly Components Inside Node.js With Jco To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.
Comments
or email your comment to: comments@i-programmer.info
<ASIN:1871962889> <ASIN:1871962420> |
Last Updated ( Wednesday, 25 September 2024 ) |