HN user

codermike

70 karma

Software engineer https://coder-mike.com/ Twitter: @microvium

Posts2
Comments12
View on HN
Microvium Is Small 4 years ago

Yes, the parking meter example is an exact case I ran into in real life. But Microvium didn't exist back then.

But in general, an IoT solution may have some business logic or rules that transcends the specific device, and some may prefer to represent that logic in a high level language like JS, and some situations may benefit from being able to access that logic from multiple places -- e.g. front-end, back-end, and device.

Microvium Is Small 4 years ago

It calls malloc once or twice when you resume a snapshot. The first malloc includes core persistent state (e.g. memory stats counters, etc), and global variables in the script. If there is any heap in the snapshot, the second malloc is for the initial heap.

Then it calls malloc when you call from C in JS -- about 300B by default. This is to allocate the core registers and virtual stack. It frees it when the JS has fully completed and control returns to the host.

Then it also calls malloc each time it runs out of space in the managed heap and needs to expand. By default these will be 256B chunks. If you use a lot of heap space, maybe you want to increase this chunk size to reduce overhead here.

And it calls malloc about once or twice each time there is a GC collection, regardless of heap size.

Microvium Is Small 4 years ago

By the way, if you’re interested, I’m the guy behind Microvium. It’s been my pet project for the last few years. It’s very motivating to see all the positive and encouraging feedback. Thank you all!

You can find me @microvium on twitter

Microvium Is Small 4 years ago

I think a proper FFI library should be distributed with Microvium for convenience, but I just haven’t gotten around to it yet. But let me try summarize how snapshotting relates..

The snapshotting paradigm means that your JS code starts executing at “compile time” and has access to the compile-time host. Microvium by default provides access to the built-in node modules while the script is executing at compile time (these become detached at runtim), so the JS code can do things like fs.writeFileSync to code-generate C code at compile time.

This means you can have a higher-level library that wraps the built in vmExport/vmImport functions while simultaneously generating the corresponding glue code.

Microvium Is Small 4 years ago

The entire purpose of Javascript is that it's a "scripting" language, so having an interactive runtime is kind of the point.

If your use case is plugging a keyboard into your MCU or connecting a terminal prompt on the UART, then the MCU needs to be running a parser, yes. But there may be many real-world use cases where your "scripts" will be going through some kind of deployment and release process, and adding a step to compile them to bytecode is easy. But YMMV depending on what you need.

not using malloc/free is actually a feature, not a bug

Microvium maintains its own managed heap which uses a compacting garabage collector, so that heap allocations there are fast O(1) and have no fragmentation. But it needs to occassionally get chunks of memory from the host/OS to expand its managed heap, which is where it uses malloc.

I agree that there are better and worse ways to use dynamic memory. I have more thoughts here: https://coder-mike.com/blog/2022/05/27/single-threading-is-m...

Microvium Is Small 4 years ago

Here are some use cases...

- If you have an IoT device and want to share logic between the device and cloud. A concrete example might be a smart parking meter where you can pay for parking on the meter itself or online or by a mobile app, and you want common business logic, tariff calculations, parking rules, user workflow, etc. You could represent the logic in C but arguably something like JS is better suited.

- You want downloadable behavior that's separate from the firmware. Maybe you're making a product with one base version of C firmware but customizable by downloading scripts. Or maybe you're an enterprise company and your customers all want behavior customization and you don't want the nightmare of managing separate firmware for each of them. In C, maybe you could do this with position-independent-code modules, but JS might just be more friendly.

- Maybe you just like JS. JS has garbage collection and closures, for example. Callback-based async logic is easier in JS. Functional-style code is easier to write. Depends what you feel comfortable with.

Perhaps not to replace C firmware, but to be able to script the higher-level behavior in a language that's more comfortable and expressive.

Microvium Is Small 4 years ago

The static analysis in Microvium does do this for the stack variables, but the heap is not bounded. It's trivial to write a for-loop or something that creates N new objects.

Yes, you make a good point. A decent chunk of the size of an engine like mJS or Elk (or XS) is the parser or bytecode compiler (XS and mJS use a bytecode compiler like Microvium but the compiler is designed to run on-device and so contributes to the ROM size by default). Microvium in some sense "cheats" by not having this built into the runtime engine.

From a purely practical standpoint though, how much does that matter? If you want to run JavaScript on a microcontroller and mJS works for your situation, then maybe Microvium will also work for your situation but will do it with less RAM and ROM overhead and more language features. The practical difference is that the build or release or deployment process for your scripts now includes an extra step. Whether you can afford that extra step depends on your situation.

From a philosophical perspective, it’s an interesting question. A Microvium app actually starts running at “compile-time” and a snapshot of the running VM state is downloaded to the target MCU to continue executing where it left off. From the perspective of the running app process, Microvium does support the `import` of JavaScript source text modules (and therefore also parsing), but it just loses that capability when the VM is moved from the compile-time host to the runtime host. So, the small runtime engine doesn’t support it, but Microvium as a whole does support it. I guess this goes back to the practical question of whether your particular application needs `eval` or dynamic `import` at runtime (post-snapshot).

You also brought up the handling of edge cases, which is a good point. No engine has 100% ECMAScript compliance, so it’s a matter of degree of nonconformity, but engines like Elk, mJS and Microvium are particularly far from compliant. Originally I didn’t call Microvium a JS engine (I called it an engine for JS-like scripts, or something like that) but I changed when I saw how other engines with similar capabilities and restrictions are calling themselves JS engines.

I hadn't heard of Toit. That's very interesting.

Moddable's XS engine is great, and covers the full ECMAScript spec. I did a bit of contract work on the XS engine a while back, and I participated for some time as an invited expert on the ECMA TC53 committee for JS on embedded systems alongside Moddable and can say that I have a lot of respect for what they've done. For people who are running large enough devices to support XS, I highly recommend it.

I created Microvium in part because over my career as a firmware engineer there was a common pattern that most of the devices I worked on were just way too small to run any of the off-the-shelf JS engines. Even on larger microcontrollers, it's a big commitment for a company to allocate 50kB+ of ROM and 1kB+ of RAM just to run JavaScript, especially since the firmware teams were dominated by C programmers who consider JS to be very low on the priority list.