Current section

Files

Jump to
orb lib orb table.ex
Raw

lib/orb/table.ex

defmodule Orb.Table do
defmodule Type do
@callback table_func_keys() :: list(atom())
end
defmacro allocate(entries) do
quote do
@wasm_table_allocations unquote(__MODULE__).__do_allocate(unquote(entries))
end
end
def __do_allocate(mod) when is_atom(mod) do
type_name = mod.type_name()
for key <- mod.table_func_keys() do
{{mod, key}, type_name}
end
|> __do_allocate()
# __do_allocate(mod.table_entries())
end
def __do_allocate(list) when is_list(list) do
list
end
defmodule Allocations do
@moduledoc false
defstruct lookup_table: []
def from_attribute(accumulated_value) do
lookup_table =
accumulated_value
|> Enum.reverse()
|> List.flatten()
|> Enum.with_index(fn {key, type}, index ->
{key, {index, type}}
end)
|> Map.new()
%__MODULE__{lookup_table: lookup_table}
end
def fetch!(%__MODULE__{lookup_table: lookup_table}, key) do
case Map.fetch(lookup_table, key) do
:error ->
{table_module, table_key} = key
raise "Could not find elem key #{inspect(table_key)} from table module #{table_module} in table allocations #{inspect(lookup_table)}"
{:ok, result} ->
result
end
end
def fetch_index!(%__MODULE__{} = self, key) do
{elem_index, _type} = fetch!(self, key)
elem_index
end
end
# def elem(f = %Orb.Func{}) when is_atom(f.name) do
# update_in(f.table_elem_refs, fn refs -> [f.name | refs] end)
# end
def do_elem(caller_mod, f, mod, key) do
# if Process.put(Orb.DSL, false) do
if function_exported?(caller_mod, :__wasm_table_allocations__, 0) do
Orb.Func.__add_table_elem(
f,
Allocations.fetch_index!(caller_mod.__wasm_table_allocations__(), {mod, key})
)
else
f
end
end
defmacro elem!(f, mod, key) do
caller_mod = __CALLER__.module
quote do
unquote(__MODULE__).do_elem(unquote(caller_mod), unquote(f), unquote(mod), unquote(key))
# Orb.Func.__add_table_elem(unquote(f), Allocations.fetch_index!(unquote(caller_mod).__wasm_table_allocations__(), {unquote(mod), unquote(key)}))
end
end
defmacro fetch!(key) do
quote do
Allocations.fetch!(__wasm_table_allocations__(), unquote(key))
end
end
defmacro lookup!(key) do
caller_mod = __CALLER__.module
quote do
Allocations.fetch_index!(unquote(caller_mod).__wasm_table_allocations__(), unquote(key))
end
end
defmacro lookup!(table_mod, key) do
caller_mod = __CALLER__.module
quote do
Allocations.fetch_index!(
unquote(caller_mod).__wasm_table_allocations__(),
{unquote(table_mod), unquote(key)}
)
end
end
# def elem(f = %Orb.Func{}, elem_ref) when is_function(elem_ref) do
# update_in(f.table_elem_refs, fn refs -> [elem_ref | refs] end)
# end
defmodule CallIndirect do
@moduledoc false
defstruct pop_type: nil,
push_type: nil,
type_signature: nil,
table_index: 0,
arguments: []
defimpl Orb.ToWat do
def to_wat(
%Orb.Table.CallIndirect{
type_signature: type_signature,
table_index: table_index,
arguments: arguments
},
indent
) do
[
indent,
"(call_indirect (type $",
to_string(type_signature),
")",
for(arg <- arguments, do: [" ", Orb.ToWat.to_wat(arg, "")]),
" (i32.const ",
to_string(table_index),
?),
?)
]
end
end
end
def call({table_index, type_signature}) do
%CallIndirect{type_signature: type_signature, table_index: table_index}
end
def call({table_index, type_signature}, arg1) do
%CallIndirect{type_signature: type_signature, table_index: table_index, arguments: [arg1]}
end
def call({table_index, type_signature}, arg1, arg2) do
%CallIndirect{
type_signature: type_signature,
table_index: table_index,
arguments: [arg1, arg2]
}
end
def call({table_index, type_signature}, arg1, arg2, arg3) do
%CallIndirect{
type_signature: type_signature,
table_index: table_index,
arguments: [arg1, arg2, arg3]
}
end
def call({table_index, type_signature}, arg1, arg2, arg3, arg4) do
%CallIndirect{
type_signature: type_signature,
table_index: table_index,
arguments: [arg1, arg2, arg3, arg4]
}
end
def call_indirect(func_type, type_signature, table_index) do
do_call_indirect(func_type, type_signature, table_index, [])
end
def call_indirect(func_type, type_signature, table_index, arg1) do
do_call_indirect(func_type, type_signature, table_index, [arg1])
end
def call_indirect(func_type, type_signature, table_index, arg1, arg2) do
do_call_indirect(func_type, type_signature, table_index, [arg1, arg2])
end
def call_indirect(func_type, type_signature, table_index, arg1, arg2, arg3) do
do_call_indirect(func_type, type_signature, table_index, [arg1, arg2, arg3])
end
def call_indirect(func_type, type_signature, table_index, arg1, arg2, arg3, arg4) do
do_call_indirect(func_type, type_signature, table_index, [arg1, arg2, arg3, arg4])
end
defp do_call_indirect(func_type = %Orb.Func.Type{}, type_signature, table_index, arguments) do
%CallIndirect{
pop_type: func_type.params,
# pop_type: if(func_type.params, do: for(param <- func_type.params, do: param.type)),
push_type: func_type.result,
type_signature: type_signature,
table_index: table_index,
arguments: arguments
}
end
end