`JS_NewClassID(rt, &class_id)` where `class_id` is a global variable
is unsafe when called from multiple threads but that is exactly what
quickjs-libc.c did.
Add a new JS_AddRuntimeFinalizer function that lets quickjs-libc
store the class ids in JSRuntimeState and defer freeing the memory
until the runtime is destroyed. Necessary because object finalizers
such as js_std_file_finalizer need to know the class id and run after
js_std_free_handlers runs.
Fixes: https://github.com/quickjs-ng/quickjs/issues/577
Make sure the one set in the malloc functions is used rather than the
default one, since it will likely use a different allocator.
For some reason, this didn't cause a problem on macOS, but it does in
Linux. Opsie! Added some CI to prevent these kinds of bugs.
After 56da486312 it's possible existing
code relied on the current exception not being null to dump it, and the
dumped value just said "[unsupported type]". This change provides a more
descriptive value.
Rather than having the user take care of JSMallocState, take care of the
bookkeeping internally (and make JSMallocState non-public since it's no
longer necessary) and keep the allocation functions to the bare minimum.
This has the advantage that using a different allocator is just a few
lines of code, and there is no need to copy the default implementation
just to moficy the call to the allocation function.
Fixes: https://github.com/quickjs-ng/quickjs/issues/285
The spec says HostMakeJobCallback has to be used on the callback: https://tc39.es/ecma262/multipage/managing-memory.html#sec-finalization-registry-cleanup-callback
That makes the following (arguably contrived) example run forever until
memory is exhausted.
```js
let count = 0;
function main() {
console.log(`main! ${++count}`);
const registry = new FinalizationRegistry(() => {
globalThis.foo = main();
});
registry.register([]);
registry.register([]);
return registry;
}
main();
console.log(count);
```
That is unlike V8, which runs 0 times. This can be explained by the
difference in GC implementations and since FinRec makes GC observable,
here we are!
Fixes: https://github.com/quickjs-ng/quickjs/issues/432
Analogously to JS_WriteObject2, it allows the user to get a tab with all
the SAB objects that were read.
This can help adjust reference counts in a scenario where a SAB that was
written increased it and it's necessary to decrease it upon reading it.