RoyalIcing / Orb

Write WebAssembly with Elixir
https://useorb.dev
BSD 3-Clause "New" or "Revised" License
217 stars 4 forks source link

Read memory offset, incorporating size of statically allocated pages for string constants #22

Open RoyalIcing opened 8 months ago

RoyalIcing commented 8 months ago

Currently the string constants are just thrown into memory from offset 0xFF. You must write Memory.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).

RoyalIcing commented 7 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.

RoyalIcing commented 7 months ago

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.

RoyalIcing commented 5 months ago

This is now implemented, and it was much easier than anticipated!

RoyalIcing commented 5 months ago

SilverOrb.Arena still needs a way to read the page offset it has been allocated.