Instead, finalizers just get access to the foreign object's raw bytes.
This is deliberately limiting, since it discourages the user from
interacting with the VM in the middle of a GC.
This turns those functions into general-purpose functions for writing
raw C values into slots on the foreign call stack.
Writing a return just means writing a value to slot 0.
- wrenGetArgumentCount() -> wrenGetSlotCount()
- wrenGetArgument___() -> wrenGetSlot___()
Also, the get functions assert that the value is the right type instead
of checking at runtime. This puts the onus on the caller to be safe,
but maximizes performance.
I've got some ideas on how to tweak the embedding API, but I want to
see what performance impact they have first, so this adds a little
benchmark that just calls a foreign method a ton of times.
Most of the pieces are there:
- You can declare a foreign class.
- It will call your C function to provide an allocator function.
- Whenever a foreign object is created, it calls the allocator.
- Foreign methods can access the foreign bytes of an object.
- Most of the runtime checking is in place for things like subclassing
foreign classes.
There is still some loose ends to tie up:
- Finalizers are not called.
- Some of the error-handling could be better.
- The GC doesn't track how much memory a marked foreign object uses.