Open RoyalIcing opened 8 months ago
Having done a little investigation this looks difficult. We calculate all the constants when compiling the entire module.
# lib/orb.ex:637
def __wasm_module__() do
%{body: body, constants: constants, global_definitions: global_definitions} =
Orb.Compiler.run(__MODULE__, @wasm_globals)
Orb.ModuleDefinition.new(…)
end
So if we want to use the constants size at WebAssembly compile time then we have a chicken-egg problem. We use this for SilverOrb.Arena to work out which page offset an arena has allocated. So it needs to know that at compile-time.
I don’t want to compile twice as there’s a risk that state changes between the two and it results into two slightly different compiled outputs. And knowing the size of the constants would be a state change.
I'm thinking the easiest way to solve this is to have a WebAssembly global store the constant size. Operations like with arenas can just read that global.
A small pass just before assembly will set the initial value of the global. It only needs to be a read-only global.
This is now implemented, and it was much easier than anticipated!
SilverOrb.Arena
still needs a way to read the page offset it has been allocated.
Currently the string constants are just thrown into memory from offset
0xFF
. You must writeMemory.pages(1)
for string constants to even work — this sucks!What we should do is count how many bytes the string constants take and allocate an exact number of memory pages for them. e.g.
80 KiB
of constants should allocate 2 pages. I don’t think we are so memory tight that we have to compress memory, so the left over memory on the last page for constants would just remain unused.I intend to switch how String pointers are represented (See #7) but we’d still likely put
0x0
nul bytes between each string. This makes raw memory easier to debug, and possibly is useful for interop that expects nul-terminated strings (but I’m still learning whether these are something to avoid like the plague).