Skip to content

Commit

Permalink
Implement bump alloc for Arena
Browse files Browse the repository at this point in the history
  • Loading branch information
RoyalIcing committed Oct 30, 2023
1 parent d6d2a11 commit 6308c8b
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 27 deletions.
3 changes: 3 additions & 0 deletions lib/orb/memory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ defmodule Orb.Memory do
end
end

@page_byte_size 64 * 1024
def page_byte_size(), do: @page_byte_size

@doc """
Declare how many 64Kib pages of memory your module needs.
Expand Down
58 changes: 41 additions & 17 deletions test/examples/arena.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,49 @@ defmodule Examples.Arena do

use Orb

alias Orb.Instruction

def alloc_impl(values_mod, byte_count) do
offset_global_name = values_mod.offset_global_name()
start_offset = values_mod.start_offset()
end_offset = values_mod.end_offset()

Orb.snippet Orb.S32, new_ptr: I32.UnsafePointer do
new_ptr = Instruction.global_get(Orb.I32, offset_global_name)
Instruction.global_set(Orb.I32, offset_global_name, new_ptr + byte_count)

if Instruction.global_get(Orb.I32, offset_global_name) > end_offset * Orb.Memory.page_byte_size() do
unreachable!()
end

new_ptr
end
end

defmacro def(name, opts) do
# module_name = Module.concat(__MODULE__, Macro.expand_literals(name, __CALLER__))
# Module.put_attribute(module_name, :wasm_func_prefix, module_name)

quote do
require Orb.Memory
page_offset = Orb.Memory.pages(unquote(opts[:pages]))

module_name = Module.concat(__MODULE__, unquote(name))

page_count = unquote(opts[:pages])
page_offset = Orb.Memory.pages(page_count)
offset_global_name =
String.to_atom("#{Macro.inspect_atom(:literal, module_name)}.bump_offset")

Module.create(
Module.concat([__MODULE__, unquote(name), Values]),
quote do
def start_offset(), do: unquote(page_offset)
def end_offset(), do: unquote(page_offset + page_count)
def offset_global_name(), do: unquote(offset_global_name)
end,
unquote(Macro.Env.location(__CALLER__))
)


global(
do: [
{offset_global_name, page_offset * 64 * 1024}
Expand All @@ -36,27 +66,21 @@ defmodule Examples.Arena do
# end

with do
Module.create(module_name, quote do
use Orb
Orb.__mode_pre(Orb.S32)

# offset_global_name = unquote(offset_global_name)
defmodule unquote(name) do
use Orb

set_func_prefix(inspect(unquote(module_name)))
alias __MODULE__.Values

# @wasm_func_prefix inspect(unquote(module_name))
# Module.put_attribute(__MODULE__, :wasm_func_prefix, inspect(unquote(module_name)))
# IO.puts("put_attribute")
# IO.inspect(__MODULE__)
# IO.inspect(inspect(unquote(module_name)))
set_func_prefix(inspect(__MODULE__))

# https://man7.org/linux/man-pages/man3/alloca.3.html
defw alloc(byte_count: I32), I32.UnsafePointer do
0x0
# push(global_get(unquote(offset_global_name))) do
# @bump_offset = I32.add(@bump_offset, size)
# end
defw alloc(byte_count: I32), I32.UnsafePointer, new_ptr: I32.UnsafePointer do
# Examples.Arena.alloc_impl(Values, byte_count)
Examples.Arena.alloc_impl(Values, Instruction.local_get(I32, :byte_count))
end
end, unquote(Macro.Env.location(__CALLER__)))
end
end

# Orb.include(module_name)
Expand Down
62 changes: 52 additions & 10 deletions test/examples/arena_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,69 @@ defmodule Examples.ArenaTest do
Arena.def(First, pages: 2)
Arena.def(Second, pages: 3)

defw test(), I32 do
defw test(), {I32, I32, I32} do
First.alloc(16)
First.alloc(16)
Second.alloc(16)
end

defw just_enough(), I32, i: I32, final: I32 do
loop HereWeGo do
final = First.alloc(16)

i = i + 1
HereWeGo.continue(if: i < 2 * 64 * 1024 / 16)
end
final
end

defw too_many(), i: I32 do
loop HereWeGo do
_ = First.alloc(16)

i = i + 1
HereWeGo.continue(if: i <= 2 * 64 * 1024 / 16)
end
end
end

test "add func prefixes" do
assert ~S"""
assert A.to_wat() =~ ~S"""
(module $A
(memory (export "memory") 5)
(global $Examples.ArenaTest.A.First.bump_offset (mut i32) (i32.const 0))
(global $Examples.ArenaTest.A.Second.bump_offset (mut i32) (i32.const 131072))
"""

assert A.to_wat() =~ ~S"""
(func $Examples.ArenaTest.A.First.alloc (param $byte_count i32) (result i32)
(i32.const 0)
)
(func $Examples.ArenaTest.A.Second.alloc (param $byte_count i32) (result i32)
(i32.const 0)
)
(func $test (export "test") (result i32)
"""

assert A.to_wat() =~ ~S"""
(func $test (export "test") (result i32 i32 i32)
(call $Examples.ArenaTest.A.First.alloc (i32.const 16))
(call $Examples.ArenaTest.A.First.alloc (i32.const 16))
(call $Examples.ArenaTest.A.Second.alloc (i32.const 16))
)
)
""" = A.to_wat()
"""
end

test "allocates separate memory offsets" do
# IO.puts(A.to_wat())
i = Instance.run(A)
f = Instance.capture(i, :test, 0)
assert f.() === {0, 16, 131072}
end

test "just enough allocations" do
i = Instance.run(A)
f = Instance.capture(i, :just_enough, 0)
assert 131056 = f.()
end

test "too many allocations" do
i = Instance.run(A)
f = Instance.capture(i, :too_many, 0)
assert {:error, _} = f.()
end
end

0 comments on commit 6308c8b

Please sign in to comment.