I was oogling with QuickJS for my custom os as the first script language, but MQJS looks like an even better fit for my low-memory footprint OS design.
For something targeting embedded systems, I'm surprised at the lack of error checking since in my mental model embedded systems are more likely to have "simple" things go wrong. But, who am I to question Fabrice, who I'm sure has forgotten more about systems programming than I will ever know
“Embedded system” covers a wide spectrum nowadays. At the low end you have something like the code running an electric toothbrush, which is kind of just an easier way to make dedicated hardware. The program is so small that you just handle all the cases directly. At the high end you have something like a home router that runs Linux and is just as complex as a “real” computer was not long ago, and probably has equally bad error handling. Somewhere in between is a range where “simple” things may go wrong, but you don’t really have a way to handle them other than rebooting anyway, so error handling looks more like aborting on an assert failure. A common last-bastion approach is a “watchdog” in the hardware that will reset everything if the software doesn’t, for whatever reason, “pet” it periodically.
(Edit: this is of course for non-critical systems — medical, automotive, avionics, etc. is in another dimension.)
Ironically, the use of a static memory buffer makes it harder for us to use in an embedded context. We currently use Microvium and it’s great on microcontrollers. It can dynamically grow the heap and then free that memory after a compacting GC phase. We can easily have multiple independent JS VMs on a device, each running a different phase of operation, backed by the same memory with each VM using memory between invocations only to persist heap objects that survive between runs (typically using about 128 bytes per VM). On a device with 128 KiB of RAM, it’s quite feasible to have half a dozen or more isolated JS VMs. The code size of Microvium on the device is about 14 KiB, with under 1 KiB per VM in the idle state.
I hesitate to cite examples for fear of bringing down the whataboutism brigade but the two that I've always been taught are "merely requests" are malloc and read. I am pretty sure both are retryable so its not even fatal if they come back "nope" or with a short read. I didn't study the JS-api side of things in order to be able to spot bad type conversions/assertions, but hopefully those would just terminate the script and not the runtime as would a null deference. I also only recently learned that malloc on Linux has an additional onoz in that it mostly just says yes and lets the OOMkiller sort out the details :-(
I really like the stricter mode and especially the "no holes" on Arrays: in my JS engine Arrays are already always dense from a memory perspective but can contain hole values. It has been my intention to make truly dense (no holes but undefined) Arrays an option but haven't gotten around to it.
Now that we have mqjs version of that, I believe I'll be copying their semantics fully do as to not split the space further.
abetusk | a day ago
Github user
bellardis Fabrice Bellard of FFMPEG and TCC fame.sebastien | a day ago
He's so prolific, and many of his projects are well known and used by many. He should be as famous as Torvalds or Carmack, I think!
peter-leonov | a day ago
QEMU! Thanks for pointing out.
xq | a day ago
That's such a christmas gift
I was oogling with QuickJS for my custom os as the first script language, but MQJS looks like an even better fit for my low-memory footprint OS design.
mdaniel | a day ago
For something targeting embedded systems, I'm surprised at the lack of error checking since in my mental model embedded systems are more likely to have "simple" things go wrong. But, who am I to question Fabrice, who I'm sure has forgotten more about systems programming than I will ever know
wrs | 22 hours ago
“Embedded system” covers a wide spectrum nowadays. At the low end you have something like the code running an electric toothbrush, which is kind of just an easier way to make dedicated hardware. The program is so small that you just handle all the cases directly. At the high end you have something like a home router that runs Linux and is just as complex as a “real” computer was not long ago, and probably has equally bad error handling. Somewhere in between is a range where “simple” things may go wrong, but you don’t really have a way to handle them other than rebooting anyway, so error handling looks more like aborting on an assert failure. A common last-bastion approach is a “watchdog” in the hardware that will reset everything if the software doesn’t, for whatever reason, “pet” it periodically.
(Edit: this is of course for non-critical systems — medical, automotive, avionics, etc. is in another dimension.)
david_chisnall | 9 hours ago
Ironically, the use of a static memory buffer makes it harder for us to use in an embedded context. We currently use Microvium and it’s great on microcontrollers. It can dynamically grow the heap and then free that memory after a compacting GC phase. We can easily have multiple independent JS VMs on a device, each running a different phase of operation, backed by the same memory with each VM using memory between invocations only to persist heap objects that survive between runs (typically using about 128 bytes per VM). On a device with 128 KiB of RAM, it’s quite feasible to have half a dozen or more isolated JS VMs. The code size of Microvium on the device is about 14 KiB, with under 1 KiB per VM in the idle state.
Oh, and the GC design of Microvium also integrates trivially with our hardware temporal safety mechanism, so we don’t have memory corruption issues with C code interfacing with JavaScript.
reivilibre | 8 hours ago
What do you mean by lack of error checking / what's this in reference to?
The readme seems to say that MQuickJS is more strict than usual
mdaniel | an hour ago
I hesitate to cite examples for fear of bringing down the whataboutism brigade but the two that I've always been taught are "merely requests" are
mallocandread. I am pretty sure both are retryable so its not even fatal if they come back "nope" or with a short read. I didn't study the JS-api side of things in order to be able to spot bad type conversions/assertions, but hopefully those would just terminate the script and not the runtime as would a null deference. I also only recently learned that malloc on Linux has an additional onoz in that it mostly just says yes and lets the OOMkiller sort out the details :-(aapoalas | 5 hours ago
I really like the stricter mode and especially the "no holes" on Arrays: in my JS engine Arrays are already always dense from a memory perspective but can contain hole values. It has been my intention to make truly dense (no holes but undefined) Arrays an option but haven't gotten around to it.
Now that we have mqjs version of that, I believe I'll be copying their semantics fully do as to not split the space further.