LibWasm: Split parameters from locals

This commit is contained in:
Ali Mohammad Pur 2025-11-07 11:29:20 +01:00 committed by Ali Mohammad Pur
parent ac979648bd
commit b89ecfc6bc
15 changed files with 153 additions and 53 deletions

View file

@ -293,7 +293,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
config.enable_instruction_count_limit();
config.set_frame(Frame {
auxiliary_instance,
Vector<Value> {},
{},
{},
entry.expression(),
1,
});
@ -315,7 +316,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
config.enable_instruction_count_limit();
config.set_frame(Frame {
main_module_instance,
Vector<Value> {},
{},
{},
entry,
entry.instructions().size() - 1,
});
@ -350,7 +352,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
config.enable_instruction_count_limit();
config.set_frame(Frame {
main_module_instance,
Vector<Value> {},
{},
{},
active_ptr->expression,
1,
});
@ -385,7 +388,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector<Ex
config.enable_instruction_count_limit();
config.set_frame(Frame {
main_module_instance,
Vector<Value> {},
{},
{},
data.offset,
1,
});

View file

@ -315,10 +315,7 @@ private:
class ModuleInstance {
public:
explicit ModuleInstance(
Vector<FunctionType> types, Vector<FunctionAddress> function_addresses, Vector<TableAddress> table_addresses,
Vector<MemoryAddress> memory_addresses, Vector<GlobalAddress> global_addresses, Vector<DataAddress> data_addresses,
Vector<TagAddress> tag_addresses, Vector<TagType> tag_types,
Vector<ExportInstance> exports)
Vector<FunctionType> types, Vector<FunctionAddress> function_addresses, Vector<TableAddress> table_addresses, Vector<MemoryAddress> memory_addresses, Vector<GlobalAddress> global_addresses, Vector<DataAddress> data_addresses, Vector<TagAddress> tag_addresses, Vector<TagType> tag_types, Vector<ExportInstance> exports)
: m_types(move(types))
, m_tag_types(move(tag_types))
, m_functions(move(function_addresses))
@ -392,7 +389,7 @@ private:
class HostFunction {
public:
explicit HostFunction(AK::Function<Result(Configuration&, Vector<Value>&)> function, FunctionType const& type, ByteString name)
explicit HostFunction(AK::Function<Result(Configuration&, Span<Value>)> function, FunctionType const& type, ByteString name)
: m_function(move(function))
, m_type(type)
, m_name(move(name))
@ -404,7 +401,7 @@ public:
auto& name() const { return m_name; }
private:
AK::Function<Result(Configuration&, Vector<Value>&)> m_function;
AK::Function<Result(Configuration&, Span<Value>)> m_function;
FunctionType m_type;
ByteString m_name;
};
@ -672,8 +669,9 @@ private:
class Frame {
public:
explicit Frame(ModuleInstance const& module, Vector<Value> locals, Expression const& expression, size_t arity)
explicit Frame(ModuleInstance const& module, Vector<Value, 8> arguments, Vector<Value, 8> locals, Expression const& expression, size_t arity)
: m_module(module)
, m_arguments(move(arguments))
, m_locals(move(locals))
, m_expression(expression)
, m_arity(arity)
@ -683,13 +681,23 @@ public:
auto& module() const { return m_module; }
auto& locals() const { return m_locals; }
auto& locals() { return m_locals; }
auto& arguments() const { return m_arguments; }
auto& arguments() { return m_arguments; }
auto& expression() const { return m_expression; }
auto arity() const { return m_arity; }
auto label_index() const { return m_label_index; }
auto& label_index() { return m_label_index; }
Value& local_or_argument(LocalIndex index)
{
if (index.value() & LocalArgumentMarker)
return m_arguments[index.value() & ~LocalArgumentMarker];
return m_locals[index.value()];
}
private:
ModuleInstance const& m_module;
Vector<Value, 8> m_arguments;
Vector<Value, 8> m_locals;
Expression const& m_expression;
size_t m_arity { 0 };

View file

@ -137,9 +137,9 @@ struct Continue {
static Outcome operator()(BytecodeInterpreter& interpreter, Configuration& configuration, Instruction const*, SourcesAndDestination addresses, u64 current_ip_value, Dispatch const* cc)
{
current_ip_value++;
addresses.sources_and_destination = cc[current_ip_value].sources_and_destination;
auto const instruction = cc[current_ip_value].instruction;
auto const handler = bit_cast<Outcome (*)(HANDLER_PARAMS(DECOMPOSE_PARAMS_TYPE_ONLY))>(cc[current_ip_value].handler_ptr);
addresses.sources_and_destination = cc[current_ip_value].sources_and_destination;
TAILCALL return handler(interpreter, configuration, instruction, addresses, current_ip_value, cc);
}
};
@ -1027,6 +1027,12 @@ HANDLE_INSTRUCTION(local_get)
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
HANDLE_INSTRUCTION(synthetic_argument_get)
{
configuration.push_to_destination(configuration.argument(instruction->local_index()), addresses.destination);
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
HANDLE_INSTRUCTION(i32_const)
{
configuration.push_to_destination(Value(instruction->arguments().unsafe_get<i32>()), addresses.destination);
@ -1035,39 +1041,39 @@ HANDLE_INSTRUCTION(i32_const)
HANDLE_INSTRUCTION(synthetic_i32_add2local)
{
configuration.push_to_destination(Value(static_cast<i32>(Operators::Add {}(configuration.local(instruction->local_index()).to<u32>(), configuration.local(instruction->arguments().get<LocalIndex>()).to<u32>()))), addresses.destination);
configuration.push_to_destination(Value(static_cast<i32>(Operators::Add {}(configuration.local_or_argument(instruction->local_index()).to<u32>(), configuration.local_or_argument(instruction->arguments().get<LocalIndex>()).to<u32>()))), addresses.destination);
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
HANDLE_INSTRUCTION(synthetic_i32_addconstlocal)
{
configuration.push_to_destination(Value(static_cast<i32>(Operators::Add {}(configuration.local(instruction->local_index()).to<u32>(), instruction->arguments().unsafe_get<i32>()))), addresses.destination);
configuration.push_to_destination(Value(static_cast<i32>(Operators::Add {}(configuration.local_or_argument(instruction->local_index()).to<u32>(), instruction->arguments().unsafe_get<i32>()))), addresses.destination);
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
HANDLE_INSTRUCTION(synthetic_i32_andconstlocal)
{
configuration.push_to_destination(Value(Operators::BitAnd {}(configuration.local(instruction->local_index()).to<i32>(), instruction->arguments().unsafe_get<i32>())), addresses.destination);
configuration.push_to_destination(Value(Operators::BitAnd {}(configuration.local_or_argument(instruction->local_index()).to<i32>(), instruction->arguments().unsafe_get<i32>())), addresses.destination);
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
HANDLE_INSTRUCTION(synthetic_i32_storelocal)
{
if (interpreter.store_value(configuration, *instruction, ConvertToRaw<i32> {}(configuration.local(instruction->local_index()).to<i32>()), 0, addresses))
if (interpreter.store_value(configuration, *instruction, ConvertToRaw<i32> {}(configuration.local_or_argument(instruction->local_index()).to<i32>()), 0, addresses))
return Outcome::Return;
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
HANDLE_INSTRUCTION(synthetic_i64_storelocal)
{
if (interpreter.store_value(configuration, *instruction, ConvertToRaw<i64> {}(configuration.local(instruction->local_index()).to<i64>()), 0, addresses))
if (interpreter.store_value(configuration, *instruction, ConvertToRaw<i64> {}(configuration.local_or_argument(instruction->local_index()).to<i64>()), 0, addresses))
return Outcome::Return;
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
HANDLE_INSTRUCTION(synthetic_local_seti32_const)
{
configuration.local(instruction->local_index()) = Value(instruction->arguments().unsafe_get<i32>());
configuration.local_or_argument(instruction->local_index()) = Value(instruction->arguments().unsafe_get<i32>());
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
@ -1181,7 +1187,7 @@ HANDLE_INSTRUCTION(nop)
HANDLE_INSTRUCTION(local_set)
{
// bounds checked by verifier.
configuration.local(instruction->local_index()) = configuration.take_source(0, addresses.sources);
configuration.local_or_argument(instruction->local_index()) = configuration.take_source(0, addresses.sources);
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
@ -1577,7 +1583,7 @@ HANDLE_INSTRUCTION(local_tee)
auto value = configuration.source_value(0, addresses.sources); // bounds checked by verifier.
auto local_index = instruction->local_index();
dbgln_if(WASM_TRACE_DEBUG, "stack:peek -> locals({})", local_index.value());
configuration.frame().locals()[local_index.value()] = value;
configuration.frame().local_or_argument(local_index) = value;
TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY));
}
@ -4044,7 +4050,7 @@ Outcome BytecodeInterpreter::call_address(Configuration& configuration, Function
if (source == CallAddressSource::IndirectCall || source == CallAddressSource::IndirectTailCall) {
TRAP_IF_NOT(type->parameters().size() <= configuration.value_stack().size());
}
Vector<Value> args;
Vector<Value, 8> args;
if (!type->parameters().is_empty()) {
args.ensure_capacity(type->parameters().size());
auto span = configuration.value_stack().span().slice_from_end(type->parameters().size());
@ -4478,6 +4484,21 @@ CompiledInstructions try_compile_instructions(Expression const& expression, Span
result.dispatches.remove_all(nops_to_remove, [](auto const& it) { return it.key(); });
// Rewrite local.get of arguments to argument.get to keep local.get for locals only.
for (size_t i = 0; i < result.dispatches.size(); ++i) {
auto& dispatch = result.dispatches[i];
if (dispatch.instruction->opcode() == Instructions::local_get) {
auto local_index = dispatch.instruction->local_index();
if (local_index.value() & LocalArgumentMarker) {
result.extra_instruction_storage.append(Instruction(
Instructions::synthetic_argument_get,
local_index));
result.dispatches[i].instruction = &result.extra_instruction_storage.unsafe_last();
result.dispatches[i].instruction_opcode = result.dispatches[i].instruction->opcode();
}
}
}
// Allocate registers for instructions, meeting the following constraints:
// - Any instruction that produces polymorphic stack, or requires its inputs on the stack must sink all active values to the stack.
// - All instructions must have the same location for their last input and their destination value (if any).

View file

@ -16,17 +16,18 @@ void Configuration::unwind_impl()
m_frame_stack.take_last();
m_depth--;
m_locals_base = m_frame_stack.is_empty() ? nullptr : m_frame_stack.unchecked_last().locals().data();
m_arguments_base = m_frame_stack.is_empty() ? nullptr : m_frame_stack.unchecked_last().arguments().data();
}
Result Configuration::call(Interpreter& interpreter, FunctionAddress address, Vector<Value> arguments)
Result Configuration::call(Interpreter& interpreter, FunctionAddress address, Vector<Value, 8> arguments)
{
if (auto fn = TRY(prepare_call(address, arguments)); fn.has_value())
return fn->function()(*this, arguments);
return fn->function()(*this, arguments.span());
m_ip = 0;
return execute(interpreter);
}
ErrorOr<Optional<HostFunction&>, Trap> Configuration::prepare_call(FunctionAddress address, Vector<Value>& arguments, bool is_tailcall)
ErrorOr<Optional<HostFunction&>, Trap> Configuration::prepare_call(FunctionAddress address, Vector<Value, 8>& arguments, bool is_tailcall)
{
auto* function = m_store.get(address);
if (!function)
@ -35,15 +36,16 @@ ErrorOr<Optional<HostFunction&>, Trap> Configuration::prepare_call(FunctionAddre
if (auto* wasm_function = function->get_pointer<WasmFunction>()) {
if (is_tailcall)
unwind_impl(); // Unwind the current frame, the "return" in the tail-called function will unwind the frame we're gonna push now.
Vector<Value> locals = move(arguments);
locals.ensure_capacity(locals.size() + wasm_function->code().func().locals().size());
Vector<Value, 8> locals;
locals.ensure_capacity(wasm_function->code().func().total_local_count());
for (auto& local : wasm_function->code().func().locals()) {
for (size_t i = 0; i < local.n(); ++i)
locals.append(Value(local.type()));
locals.unchecked_append(Value(local.type()));
}
set_frame(Frame {
wasm_function->module(),
move(arguments),
move(locals),
wasm_function->code().func().body(),
wasm_function->type().results().size(),

View file

@ -35,6 +35,7 @@ public:
m_frame_stack.append(move(frame));
m_label_stack.append(label);
m_locals_base = m_frame_stack.unchecked_last().locals().data();
m_arguments_base = m_frame_stack.unchecked_last().arguments().data();
}
ALWAYS_INLINE auto& frame() const { return m_frame_stack.unchecked_last(); }
ALWAYS_INLINE auto& frame() { return m_frame_stack.unchecked_last(); }
@ -49,7 +50,15 @@ public:
ALWAYS_INLINE auto& store() const { return m_store; }
ALWAYS_INLINE auto& store() { return m_store; }
ALWAYS_INLINE Value const* raw_locals() const { return m_locals_base; }
ALWAYS_INLINE Value& local_or_argument(LocalIndex index)
{
if (index.value() & LocalArgumentMarker)
return m_arguments_base[index.value() & ~LocalArgumentMarker];
return m_locals_base[index.value()];
}
ALWAYS_INLINE Value const& argument(LocalIndex index) const { return m_arguments_base[index.value() & ~LocalArgumentMarker]; }
ALWAYS_INLINE Value& argument(LocalIndex index) { return m_arguments_base[index.value() & ~LocalArgumentMarker]; }
ALWAYS_INLINE Value const& local(LocalIndex index) const { return m_locals_base[index.value()]; }
ALWAYS_INLINE Value& local(LocalIndex index) { return m_locals_base[index.value()]; }
@ -69,8 +78,8 @@ public:
};
void unwind(Badge<CallFrameHandle>, CallFrameHandle const&) { unwind_impl(); }
ErrorOr<Optional<HostFunction&>, Trap> prepare_call(FunctionAddress, Vector<Value>& arguments, bool is_tailcall = false);
Result call(Interpreter&, FunctionAddress, Vector<Value> arguments);
ErrorOr<Optional<HostFunction&>, Trap> prepare_call(FunctionAddress, Vector<Value, 8>& arguments, bool is_tailcall = false);
Result call(Interpreter&, FunctionAddress, Vector<Value, 8> arguments);
Result execute(Interpreter&);
void enable_instruction_count_limit() { m_should_limit_instruction_count = true; }
@ -126,6 +135,7 @@ private:
u64 m_ip { 0 };
bool m_should_limit_instruction_count { false };
Value* m_locals_base { nullptr };
Value* m_arguments_base { nullptr };
};
}

View file

@ -261,6 +261,7 @@ ErrorOr<void, ValidationError> Validator::validate(CodeSection const& section)
auto function_validator = fork();
function_validator.m_context.locals = {};
function_validator.m_context.locals.extend(function_type.parameters());
function_validator.m_context.current_function_parameter_count = function_type.parameters().size();
for (auto& local : function.locals()) {
for (size_t i = 0; i < local.n(); ++i)
function_validator.m_context.locals.append(local.type());
@ -1362,8 +1363,7 @@ VALIDATE_INSTRUCTION(select_typed)
// https://webassembly.github.io/spec/core/bikeshed/#variable-instructions%E2%91%A2
VALIDATE_INSTRUCTION(local_get)
{
auto index = instruction.local_index();
TRY(validate(index));
auto index = TRY(validate(instruction.local_index()));
stack.append(m_context.locals[index.value()]);
return {};
@ -1371,8 +1371,7 @@ VALIDATE_INSTRUCTION(local_get)
VALIDATE_INSTRUCTION(local_set)
{
auto index = instruction.local_index();
TRY(validate(index));
auto index = TRY(validate(instruction.local_index()));
auto& value_type = m_context.locals[index.value()];
TRY(stack.take(value_type));
@ -1382,8 +1381,7 @@ VALIDATE_INSTRUCTION(local_set)
VALIDATE_INSTRUCTION(local_tee)
{
auto index = instruction.local_index();
TRY(validate(index));
auto index = TRY(validate(instruction.local_index()));
auto& value_type = m_context.locals[index.value()];
TRY(stack.take(value_type));

View file

@ -34,6 +34,7 @@ struct Context {
Optional<u32> data_count;
RefPtr<RefRBTree> references { make_ref_counted<RefRBTree>() };
size_t imported_function_count { 0 };
size_t current_function_parameter_count { 0 };
};
struct ValidationError : public Error {
@ -124,10 +125,15 @@ public:
return Errors::invalid("LabelIndex"sv);
}
ErrorOr<void, ValidationError> validate(LocalIndex index) const
ErrorOr<LocalIndex, ValidationError> validate(LocalIndex index) const
{
if (index.value() & LocalArgumentMarker)
index = index.value() & ~LocalArgumentMarker;
else
index = index.value() + m_context.current_function_parameter_count;
if (index.value() < m_context.locals.size())
return {};
return index;
return Errors::invalid("LocalIndex"sv);
}

View file

@ -499,7 +499,8 @@ namespace Instructions {
M(synthetic_call_21, 0xfe0000000000000bull, 2, 1) \
M(synthetic_call_30, 0xfe0000000000000cull, 3, 0) \
M(synthetic_call_31, 0xfe0000000000000dull, 3, 1) \
M(synthetic_end_expression, 0xfe0000000000000eull, 0, 0)
M(synthetic_end_expression, 0xfe0000000000000eull, 0, 0) \
M(synthetic_argument_get, 0xfe0000000000000full, 0, 1)
#define ENUMERATE_WASM_OPCODES(M) \
ENUMERATE_SINGLE_BYTE_WASM_OPCODES(M) \
@ -510,7 +511,7 @@ ENUMERATE_WASM_OPCODES(M)
#undef M
static constexpr inline OpCode SyntheticInstructionBase = 0xfe00000000000000ull;
static constexpr inline size_t SyntheticInstructionCount = 15;
static constexpr inline size_t SyntheticInstructionCount = 16;
}

View file

@ -7,6 +7,7 @@
#include <AK/ConstrainedStream.h>
#include <AK/Debug.h>
#include <AK/Endian.h>
#include <AK/Enumerate.h>
#include <AK/LEB128.h>
#include <AK/MemoryStream.h>
#include <AK/ScopeLogger.h>
@ -1472,9 +1473,31 @@ ParseResult<NonnullRefPtr<Module>> Module::parse(Stream& stream)
return ParseError::SectionSizeMismatch;
}
module_ptr->preprocess();
return module_ptr;
}
void Module::preprocess()
{
for (auto const [i, type_id] : enumerate(function_section().types())) {
if (type_id.value() >= type_section().types().size() || i >= code_section().functions().size()) {
dbgln("WASM Module preprocessing: skipping function {} with invalid type id {}", i, type_id.value());
continue;
}
auto& function = code_section().functions()[i];
auto const parameter_count = type_section().types()[type_id.value()].parameters().size();
for (auto& instruction : function.func().body().instructions()) {
auto& mutable_instruction = const_cast<Instruction&>(instruction);
if (instruction.local_index() < parameter_count)
mutable_instruction.set_local_index({}, instruction.local_index().value() | LocalArgumentMarker);
else
mutable_instruction.set_local_index({}, instruction.local_index().value() - parameter_count);
}
}
}
ByteString parse_error_to_byte_string(ParseError error)
{
switch (error) {

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/GenericShorthands.h>
#include <AK/HashMap.h>
#include <AK/TemporaryChange.h>
#include <LibWasm/AbstractMachine/AbstractMachine.h>
@ -473,8 +474,12 @@ void Printer::print(Wasm::Instruction const& instruction)
print_indent();
print("({}", instruction_name(instruction.opcode()));
if (instruction.arguments().has<u8>()) {
if (instruction.opcode() == Instructions::local_get || instruction.opcode() == Instructions::local_set || instruction.opcode() == Instructions::local_tee)
print(" (local index {})", instruction.local_index());
if (first_is_one_of(instruction.opcode(), Instructions::local_get, Instructions::local_set, Instructions::local_tee, Instructions::synthetic_argument_get)) {
if (instruction.local_index().value() & LocalArgumentMarker)
print(" (argument index {})", instruction.local_index().value() & ~LocalArgumentMarker);
else
print(" (local index {})", instruction.local_index().value());
}
print(")\n");
} else {
print(" ");
@ -485,7 +490,12 @@ void Printer::print(Wasm::Instruction const& instruction)
[&](FunctionIndex const& index) { print("(function index {})", index.value()); },
[&](GlobalIndex const& index) { print("(global index {})", index.value()); },
[&](LabelIndex const& index) { print("(label index {})", index.value()); },
[&](LocalIndex const& index) { print("(local index {})", index.value()); },
[&](LocalIndex const& index) {
if (index.value() & LocalArgumentMarker)
print("(argument index {})", index.value() & ~LocalArgumentMarker);
else
print("(local index {})", index.value());
},
[&](TableIndex const& index) { print("(table index {})", index.value()); },
[&](Instruction::IndirectCallArgs const& args) { print("(indirect (type index {}) (table index {}))", args.type.value(), args.table.value()); },
[&](Instruction::MemoryArgument const& args) { print("(memory index {} (align {}) (offset {}))", args.memory_index.value(), args.align, args.offset); },
@ -530,8 +540,12 @@ void Printer::print(Wasm::Instruction const& instruction)
[&](Vector<ValueType> const&) { print("(types...)"); },
[&](auto const& value) { print("(const {})", value); });
if (instruction.local_index().value())
print(" (local index {})", instruction.local_index().value());
if (first_is_one_of(instruction.opcode(), Instructions::local_get, Instructions::local_set, Instructions::local_tee, Instructions::synthetic_argument_get, Instructions::synthetic_local_seti32_const, Instructions::synthetic_i32_storelocal)) {
if (instruction.local_index().value() & LocalArgumentMarker)
print(" (argument index {})", instruction.local_index().value() & ~LocalArgumentMarker);
else
print(" (local index {})", instruction.local_index().value());
}
print(")\n");
}
@ -1259,5 +1273,6 @@ HashMap<Wasm::OpCode, ByteString> Wasm::Names::instruction_names {
{ Instructions::synthetic_call_30, "synthetic:call.30" },
{ Instructions::synthetic_call_31, "synthetic:call.31" },
{ Instructions::synthetic_end_expression, "synthetic:expression.end" },
{ Instructions::synthetic_argument_get, "synthetic:argument.get" },
};
HashMap<ByteString, Wasm::OpCode> Wasm::Names::instructions_by_name;

View file

@ -22,6 +22,8 @@
namespace Wasm {
class Module;
template<size_t M>
using NativeIntegralType = Conditional<M == 8, u8, Conditional<M == 16, u16, Conditional<M == 32, u32, Conditional<M == 64, u64, void>>>>;
@ -79,6 +81,8 @@ AK_TYPEDEF_DISTINCT_ORDERED_ID(u32, LabelIndex);
AK_TYPEDEF_DISTINCT_ORDERED_ID(u32, DataIndex);
AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(u32, InstructionPointer, Arithmetic, Comparison, Flags, Increment);
constexpr static inline auto LocalArgumentMarker = static_cast<LocalIndex::Type>(1) << (sizeof(LocalIndex::Type) * 8 - 1);
ParseError with_eof_check(Stream const& stream, ParseError error_if_not_eof);
template<typename T>
@ -564,6 +568,8 @@ public:
LocalIndex local_index() const { return m_local_index; }
void set_local_index(Badge<Module>, LocalIndex index) { m_local_index = index; }
private:
OpCode m_opcode { 0 };
LocalIndex m_local_index;
@ -1064,6 +1070,8 @@ public:
: m_locals(move(locals))
, m_body(move(body))
{
for (auto const& local : m_locals)
m_total_local_count += local.n();
}
auto& locals() const { return m_locals; }
@ -1071,9 +1079,12 @@ public:
static ParseResult<Func> parse(ConstrainedStream& stream, size_t size_hint);
auto total_local_count() const { return m_total_local_count; }
private:
Vector<Locals> m_locals;
Expression m_body;
size_t m_total_local_count { 0 };
};
class Code {
public:
@ -1236,6 +1247,7 @@ public:
private:
void set_validation_status(ValidationStatus status) { m_validation_status = status; }
void preprocess();
Vector<CustomSection> m_custom_sections;
TypeSection m_type_section;

View file

@ -994,7 +994,7 @@ struct InvocationOf<impl> {
return_ty.append(ValueType(ValueType::I32));
return HostFunction(
[&self, function_name](Configuration& configuration, Vector<Value>& arguments) -> Wasm::Result {
[&self, function_name](Configuration& configuration, Span<Value> arguments) -> Wasm::Result {
Tuple args = [&]<typename... Ts, auto... Is>(IndexSequence<Is...>) {
return Tuple { ABI::deserialize(ABI::to_compatible_value<Ts>(arguments[Is]))... };
}.template operator()<Args...>(MakeIndexSequence<sizeof...(Args)>());
@ -1018,9 +1018,9 @@ struct InvocationOf<impl> {
// Return values are passed as pointers, after the arguments
if constexpr (requires { &R::serialize_into; }) {
constexpr auto ResultCount = []<auto N>(void (R::*)(Array<Bytes, N>) const) { return N; }(&R::serialize_into);
ABI::serialize(*value.result(), address_spans<ResultCount>(arguments.span().slice(sizeof...(Args)), configuration));
ABI::serialize(*value.result(), address_spans<ResultCount>(arguments.slice(sizeof...(Args)), configuration));
} else {
ABI::serialize(*value.result(), address_spans<1>(arguments.span().slice(sizeof...(Args)), configuration));
ABI::serialize(*value.result(), address_spans<1>(arguments.slice(sizeof...(Args)), configuration));
}
}
// Return value is errno, we have nothing to return.

View file

@ -239,7 +239,7 @@ JS::ThrowCompletionOr<NonnullOwnPtr<Wasm::ModuleInstance>> instantiate_module(JS
// 3.2. If o is not an Object, throw a TypeError exception.
if (!value.is_object())
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, value);
return vm.throw_completion<JS::TypeError>(JS::ErrorType::IsNotAEvaluatedFrom, value.to_string_without_side_effects(), "Object"_string, MUST(String::formatted("[wasm import object][\"{}\"]", import_name.module)));
auto const& object = value.as_object();
// 3.3. Let v be ? Get(o, componentName).
@ -268,7 +268,7 @@ JS::ThrowCompletionOr<NonnullOwnPtr<Wasm::ModuleInstance>> instantiate_module(JS
// 3.4.3.1. Create a host function from v and functype, and let funcaddr be the result.
cache.add_imported_object(function);
Wasm::HostFunction host_function {
[&](auto&, auto& arguments) -> Wasm::Result {
[&](auto&, auto arguments) -> Wasm::Result {
GC::RootVector<JS::Value> argument_values { vm.heap() };
size_t index = 0;
for (auto& entry : arguments) {

View file

@ -140,7 +140,7 @@ private:
static Optional<Wasm::FunctionAddress> alloc_noop_function(Wasm::FunctionType type)
{
return m_machine.store().allocate(Wasm::HostFunction {
[](auto&, auto&) -> Wasm::Result {
[](auto&, auto) -> Wasm::Result {
// Noop, this just needs to exist.
return Wasm::Result { Vector<Wasm::Value> {} };
},

View file

@ -441,7 +441,7 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
Wasm::FunctionType function_type = { move(params), move(results) };
auto host_function = Wasm::HostFunction {
[&vm, &function, formal_params, returns, name](Wasm::Configuration&, Vector<Wasm::Value>& args) mutable -> Wasm::Result {
[&vm, &function, formal_params, returns, name](Wasm::Configuration&, Span<Wasm::Value> args) mutable -> Wasm::Result {
Vector<JS::Value> js_args;
js_args.ensure_capacity(args.size());
for (size_t i = 0; i < formal_params.size(); ++i) {
@ -671,7 +671,7 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
continue;
auto type = parse_result->type_section().types()[entry.type.get<Wasm::TypeIndex>().value()];
auto address = machine.store().allocate(Wasm::HostFunction(
[name = entry.name, type = type](auto&, auto& arguments) -> Wasm::Result {
[name = entry.name, type = type](auto&, auto arguments) -> Wasm::Result {
StringBuilder argument_builder;
bool first = true;
size_t index = 0;