Skip to content

Commit

Permalink
Add func prefixes
Browse files Browse the repository at this point in the history
Perfect for reusable libraries, as their namespacing won’t clash
  • Loading branch information
RoyalIcing committed Oct 30, 2023
1 parent be4c6a8 commit 88c4afb
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 38 deletions.
41 changes: 38 additions & 3 deletions lib/orb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,7 @@ defmodule Orb do
# TODO: rename these to orb_ prefix instead of wasm_ ?
Module.put_attribute(__MODULE__, :wasm_name, __MODULE__ |> Module.split() |> List.last())

Module.register_attribute(__MODULE__, :wasm_func_prefix, accumulate: false)
Module.register_attribute(__MODULE__, :wasm_memory, accumulate: true)

Module.register_attribute(__MODULE__, :wasm_globals, accumulate: true)
Expand Down Expand Up @@ -848,26 +849,60 @@ defmodule Orb do
end
end

defmacro set_func_prefix(func_prefix) do
quote do
@wasm_func_prefix unquote(func_prefix)
end
end

@doc """
Declare WebAssembly globals.
`mode` can be :readonly, :mutable, :export_readonly, or :export_mutable. The default is :mutable.
"""
defmacro global(mode \\ :mutable, do: block) do
quote do
unquote(block)
unquote(__global_block(:elixir, block))

with do
import Kernel, except: [@: 1]

require Orb.Global.Declare
Orb.Global.Declare.__import_mode(unquote(mode))
Orb.Global.Declare.__import_dsl(
unquote(__MODULE__).__global_mode_mutable(unquote(mode)),
unquote(__MODULE__).__global_mode_exported(unquote(mode))
)

unquote(block)
unquote(__global_block(:orb, block))
end
end
end

def __global_mode_mutable(:readonly), do: :readonly
def __global_mode_mutable(:mutable), do: :mutable
def __global_mode_mutable(:export_readonly), do: :readonly
def __global_mode_mutable(:export_mutable), do: :mutable
def __global_mode_exported(:readonly), do: :internal
def __global_mode_exported(:mutable), do: :internal
def __global_mode_exported(:export_readonly), do: :exported
def __global_mode_exported(:export_mutable), do: :exported

def __global_block(:elixir, items) when is_list(items) do

end

def __global_block(:orb, items) when is_list(items) do
require Orb.Global.Declare.DeclareDSL

quote do
for {key, value} <- unquote(items) do
Orb.Global.Declare.DeclareDSL.register_global(key, value)
end
end
end

def __global_block(_, block), do: block

@doc """
Declare a WebAssembly import for a function or global.
"""
Expand Down
59 changes: 39 additions & 20 deletions lib/orb/defw_dsl.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
defmodule Orb.DefwDSL do

defmacro wasm_mode(mode) do
mode = Macro.expand_literals(mode, __CALLER__)
Module.put_attribute(__CALLER__.module, :wasm_mode, mode)
Expand Down Expand Up @@ -54,20 +53,24 @@ defmodule Orb.DefwDSL do
end

defp define(call, visibility, result, locals, block, env) do
func_visibility = case visibility do
:internal -> :private
other -> other
end
func_visibility =
case visibility do
:internal -> :private
other -> other
end

def_kind = case visibility do
:public -> :def
:internal -> :def
:private -> :defp
end
def_kind =
case visibility do
:public -> :def
:internal -> :def
:private -> :defp
end

wasm = Orb.DSL.__define_func(call, func_visibility, [result: result, locals: locals], block, env)
ex_def = define_elixir_def(call, def_kind, result, env)

wasm =
Orb.DSL.__define_func(call, func_visibility, [result: result, locals: locals], block, env)

quote do
unquote(ex_def)

Expand All @@ -82,20 +85,36 @@ defmodule Orb.DefwDSL do
{_, meta, _} = call
# arity = length(args)

def_args = case func_args do
[] -> []
[keywords] -> (for {keyword, _type} <- keywords do
Macro.var(keyword, nil)
end)
multiple when is_list(multiple) ->
raise CompileError, line: meta[:line], file: file, description: "Cannot define function with multiple arguments, use keyword list instead."
end
def_args =
case func_args do
[] ->
[]

[keywords] ->
for {keyword, _type} <- keywords do
Macro.var(keyword, nil)
end

multiple when is_list(multiple) ->
raise CompileError,
line: meta[:line],
file: file,
description:
"Cannot define function with multiple arguments, use keyword list instead."
end

def_call = {name, meta, def_args}

quote do
unquote(def_kind)(unquote(def_call)) do
Orb.Instruction.typed_call(unquote(result), unquote(name), unquote(def_args))
Orb.Instruction.typed_call(
unquote(result),
case {@wasm_func_prefix, unquote(name)} do
{nil, name} -> name
{prefix, name} -> "#{prefix}.#{name}"
end,
unquote(def_args)
)
end
end
end
Expand Down
14 changes: 11 additions & 3 deletions lib/orb/dsl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,15 @@ defmodule Orb.DSL do

{name, args} =
case Macro.decompose_call(call) do
:error -> {Orb.DSL.__expand_identifier(call, __ENV__), []}
:error -> {quote(do: Macro.inspect_atom(:literal, unquote(call))), []}
other -> other
end

name = name
# name = name
# name = case name_prefix do
# nil -> name
# prefix -> "#{prefix}.#{name}"
# end

exported_names =
case visibility do
Expand Down Expand Up @@ -124,7 +128,11 @@ defmodule Orb.DSL do

quote do
%Orb.Func{
name: unquote(name),
name:
case {@wasm_func_prefix, unquote(name)} do
{nil, name} -> name
{prefix, name} -> "#{prefix}.#{name}"
end,
params: unquote(params),
result: unquote(result_type),
local_types: unquote(local_types),
Expand Down
59 changes: 53 additions & 6 deletions lib/orb/global.ex
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ defmodule Orb.Global do
end

defmacro register32(mutability, exported, list)
when mutability in ~w{readonly mutable}a and
exported in ~w[internal exported]a do

defmacro register32(mutability, exported, list) do
# when mutability in ~w{readonly mutable}a and
# exported in ~w[internal exported]a do
quote do
@wasm_globals (for {key, value} <- unquote(list) do
Orb.Global.new32(
Expand Down Expand Up @@ -164,10 +166,55 @@ defmodule Orb.Global do
end
end

defmacro __import_mode(:readonly), do: quote(do: import(ReadonlyDSL))
defmacro __import_mode(:mutable), do: quote(do: import(MutableDSL))
defmacro __import_mode(:export_readonly), do: quote(do: import(ExportReadonlyDSL))
defmacro __import_mode(:export_mutable), do: quote(do: import(ExportMutableDSL))
defmodule DeclareDSL do
import Kernel, except: [@: 1]

defmacro register_global(name, value) do
quote do
with do
require Orb.Global

Orb.Global.register32(
Module.get_last_attribute(__MODULE__, :wasm_global_mutability),
Module.get_last_attribute(__MODULE__, :wasm_global_exported),
[
{unquote(name), unquote(value)}
]
)
end
end
end

defmacro @{name, _meta, [arg]} do
quote do
with do
require Orb.Global

Orb.Global.register32(
Module.get_last_attribute(__MODULE__, :wasm_global_mutability),
Module.get_last_attribute(__MODULE__, :wasm_global_exported),
[
{unquote(name), unquote(arg)}
]
)
end
end
end
end

# defmacro __import_dsl(:readonly, :internal), do: quote(do: import(ReadonlyDSL))
# defmacro __import_dsl(:mutable, :internal), do: quote(do: import(MutableDSL))
# defmacro __import_dsl(:readonly, :exported), do: quote(do: import(ExportReadonlyDSL))
# defmacro __import_dsl(:mutable, :exported), do: quote(do: import(ExportMutableDSL))
defmacro __import_dsl(mutability, exported) do
quote do
import DeclareDSL
Module.put_attribute(__MODULE__, :wasm_global_mutability, unquote(mutability))
Module.put_attribute(__MODULE__, :wasm_global_exported, unquote(exported))
# @wasm_global_mutability unquote(mutability)
# @wasm_global_exported unquote(exported)
end
end
end

defmodule DSL do
Expand Down
12 changes: 8 additions & 4 deletions lib/orb/memory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ defmodule Orb.Memory do
def from([]), do: nil

def from(list) when is_list(list) do
case Enum.max(list) do
case Enum.sum(list) do
0 ->
nil

Expand All @@ -24,11 +24,15 @@ defmodule Orb.Memory do
@doc """
Declare how many 64Kib pages of memory your module needs.
Can be called multiple times: the highest value is used.
Can be called multiple times, with each summed up.
Returns the previous page count, which can be used as a start offset.
"""
defmacro pages(min_count) do
defmacro pages(page_count) do
quote do
@wasm_memory unquote(min_count)
start_offset = Enum.sum(@wasm_memory)
@wasm_memory unquote(page_count)
start_offset
end
end

Expand Down
64 changes: 64 additions & 0 deletions test/examples/arena.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
defmodule Examples.Arena do
# See https://www.rfleury.com/p/untangling-lifetimes-the-arena-allocator

use Orb

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]))

offset_global_name =
String.to_atom("#{Macro.inspect_atom(:literal, unquote(name))}.bump_offset")

global(
do: [
{offset_global_name, page_offset * 64 * 1024}
]
)

# defmodule unquote(name) do
# use Orb

# offset_global_name = unquote(offset_global_name)

# # https://man7.org/linux/man-pages/man3/alloca.3.html
# defw alloc(byte_count: I32), I32.UnsafePointer do
# push(global_get(unquote(offset_global_name))) do
# # @bump_offset = I32.add(@bump_offset, size)
# end
# end
# end

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

Module.create(module_name, quote do
use Orb

# offset_global_name = unquote(offset_global_name)

set_func_prefix(inspect(unquote(module_name)))

# @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)))

# 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
end
end, unquote(Macro.Env.location(__CALLER__)))

# alias module_name
# require module_name, as: unquote(name)
end
end
end
38 changes: 38 additions & 0 deletions test/examples/arena_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
defmodule Examples.ArenaTest do
use ExUnit.Case, async: true

Code.require_file("arena.exs", __DIR__)
alias Examples.Arena

alias OrbWasmtime.{Instance, Wasm}

defmodule A do
use Orb
require Arena

Arena.def(First, pages: 2)
Arena.def(Second, pages: 3)

Orb.include(A.First)

defw test() do
A.First.alloc(16)
end
end

test "add func prefixes" do
assert ~S"""
(module $A
(memory (export "memory") 5)
(global $First.bump_offset (mut i32) (i32.const 0))
(global $Second.bump_offset (mut i32) (i32.const 131072))
(func $Examples.ArenaTest.A.First.alloc (param $byte_count i32) (result i32)
(i32.const 0)
)
(func $test (export "test")
(call $Examples.ArenaTest.A.First.alloc (i32.const 16))
)
)
""" = A.to_wat()
end
end
Loading

0 comments on commit 88c4afb

Please sign in to comment.