diff --git a/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index 6bc28d38fd..c172b03810 100644 --- a/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -293,7 +293,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector {}, + {}, + {}, entry.expression(), 1, }); @@ -315,7 +316,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector {}, + {}, + {}, entry, entry.instructions().size() - 1, }); @@ -350,7 +352,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector {}, + {}, + {}, active_ptr->expression, 1, }); @@ -385,7 +388,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector {}, + {}, + {}, data.offset, 1, }); diff --git a/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index 13985bb8b7..c649255726 100644 --- a/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -315,10 +315,7 @@ private: class ModuleInstance { public: explicit ModuleInstance( - Vector types, Vector function_addresses, Vector table_addresses, - Vector memory_addresses, Vector global_addresses, Vector data_addresses, - Vector tag_addresses, Vector tag_types, - Vector exports) + Vector types, Vector function_addresses, Vector table_addresses, Vector memory_addresses, Vector global_addresses, Vector data_addresses, Vector tag_addresses, Vector tag_types, Vector 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&)> function, FunctionType const& type, ByteString name) + explicit HostFunction(AK::Function)> 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&)> m_function; + AK::Function)> m_function; FunctionType m_type; ByteString m_name; }; @@ -672,8 +669,9 @@ private: class Frame { public: - explicit Frame(ModuleInstance const& module, Vector locals, Expression const& expression, size_t arity) + explicit Frame(ModuleInstance const& module, Vector arguments, Vector 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 m_arguments; Vector m_locals; Expression const& m_expression; size_t m_arity { 0 }; diff --git a/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 47adcc7b96..871e6378e1 100644 --- a/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -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(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()), addresses.destination); @@ -1035,39 +1041,39 @@ HANDLE_INSTRUCTION(i32_const) HANDLE_INSTRUCTION(synthetic_i32_add2local) { - configuration.push_to_destination(Value(static_cast(Operators::Add {}(configuration.local(instruction->local_index()).to(), configuration.local(instruction->arguments().get()).to()))), addresses.destination); + configuration.push_to_destination(Value(static_cast(Operators::Add {}(configuration.local_or_argument(instruction->local_index()).to(), configuration.local_or_argument(instruction->arguments().get()).to()))), addresses.destination); TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY)); } HANDLE_INSTRUCTION(synthetic_i32_addconstlocal) { - configuration.push_to_destination(Value(static_cast(Operators::Add {}(configuration.local(instruction->local_index()).to(), instruction->arguments().unsafe_get()))), addresses.destination); + configuration.push_to_destination(Value(static_cast(Operators::Add {}(configuration.local_or_argument(instruction->local_index()).to(), instruction->arguments().unsafe_get()))), 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(), instruction->arguments().unsafe_get())), addresses.destination); + configuration.push_to_destination(Value(Operators::BitAnd {}(configuration.local_or_argument(instruction->local_index()).to(), instruction->arguments().unsafe_get())), addresses.destination); TAILCALL return continue_(HANDLER_PARAMS(DECOMPOSE_PARAMS_NAME_ONLY)); } HANDLE_INSTRUCTION(synthetic_i32_storelocal) { - if (interpreter.store_value(configuration, *instruction, ConvertToRaw {}(configuration.local(instruction->local_index()).to()), 0, addresses)) + if (interpreter.store_value(configuration, *instruction, ConvertToRaw {}(configuration.local_or_argument(instruction->local_index()).to()), 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 {}(configuration.local(instruction->local_index()).to()), 0, addresses)) + if (interpreter.store_value(configuration, *instruction, ConvertToRaw {}(configuration.local_or_argument(instruction->local_index()).to()), 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()); + configuration.local_or_argument(instruction->local_index()) = Value(instruction->arguments().unsafe_get()); 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 args; + Vector 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). diff --git a/Libraries/LibWasm/AbstractMachine/Configuration.cpp b/Libraries/LibWasm/AbstractMachine/Configuration.cpp index 7b30d9815d..2ddb66b0a6 100644 --- a/Libraries/LibWasm/AbstractMachine/Configuration.cpp +++ b/Libraries/LibWasm/AbstractMachine/Configuration.cpp @@ -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 arguments) +Result Configuration::call(Interpreter& interpreter, FunctionAddress address, Vector 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, Trap> Configuration::prepare_call(FunctionAddress address, Vector& arguments, bool is_tailcall) +ErrorOr, Trap> Configuration::prepare_call(FunctionAddress address, Vector& arguments, bool is_tailcall) { auto* function = m_store.get(address); if (!function) @@ -35,15 +36,16 @@ ErrorOr, Trap> Configuration::prepare_call(FunctionAddre if (auto* wasm_function = function->get_pointer()) { 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 locals = move(arguments); - locals.ensure_capacity(locals.size() + wasm_function->code().func().locals().size()); + Vector 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(), diff --git a/Libraries/LibWasm/AbstractMachine/Configuration.h b/Libraries/LibWasm/AbstractMachine/Configuration.h index 4f9a4c147b..1bf0d23e66 100644 --- a/Libraries/LibWasm/AbstractMachine/Configuration.h +++ b/Libraries/LibWasm/AbstractMachine/Configuration.h @@ -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 const&) { unwind_impl(); } - ErrorOr, Trap> prepare_call(FunctionAddress, Vector& arguments, bool is_tailcall = false); - Result call(Interpreter&, FunctionAddress, Vector arguments); + ErrorOr, Trap> prepare_call(FunctionAddress, Vector& arguments, bool is_tailcall = false); + Result call(Interpreter&, FunctionAddress, Vector 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 }; }; } diff --git a/Libraries/LibWasm/AbstractMachine/Validator.cpp b/Libraries/LibWasm/AbstractMachine/Validator.cpp index b46a70c393..09f756cb0c 100644 --- a/Libraries/LibWasm/AbstractMachine/Validator.cpp +++ b/Libraries/LibWasm/AbstractMachine/Validator.cpp @@ -261,6 +261,7 @@ ErrorOr 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)); diff --git a/Libraries/LibWasm/AbstractMachine/Validator.h b/Libraries/LibWasm/AbstractMachine/Validator.h index a5d237c0fd..a2a1565ba8 100644 --- a/Libraries/LibWasm/AbstractMachine/Validator.h +++ b/Libraries/LibWasm/AbstractMachine/Validator.h @@ -34,6 +34,7 @@ struct Context { Optional data_count; RefPtr references { make_ref_counted() }; 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 validate(LocalIndex index) const + ErrorOr 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); } diff --git a/Libraries/LibWasm/Opcode.h b/Libraries/LibWasm/Opcode.h index 010b6c9b72..c88a7a1748 100644 --- a/Libraries/LibWasm/Opcode.h +++ b/Libraries/LibWasm/Opcode.h @@ -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; } diff --git a/Libraries/LibWasm/Parser/Parser.cpp b/Libraries/LibWasm/Parser/Parser.cpp index 6ebb46f8e9..3d5117280f 100644 --- a/Libraries/LibWasm/Parser/Parser.cpp +++ b/Libraries/LibWasm/Parser/Parser.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1472,9 +1473,31 @@ ParseResult> 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); + 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) { diff --git a/Libraries/LibWasm/Printer/Printer.cpp b/Libraries/LibWasm/Printer/Printer.cpp index 3f607a84d9..ed1d1688fb 100644 --- a/Libraries/LibWasm/Printer/Printer.cpp +++ b/Libraries/LibWasm/Printer/Printer.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -473,8 +474,12 @@ void Printer::print(Wasm::Instruction const& instruction) print_indent(); print("({}", instruction_name(instruction.opcode())); if (instruction.arguments().has()) { - 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 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::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 Wasm::Names::instructions_by_name; diff --git a/Libraries/LibWasm/Types.h b/Libraries/LibWasm/Types.h index 86e0d608af..20ef55cd70 100644 --- a/Libraries/LibWasm/Types.h +++ b/Libraries/LibWasm/Types.h @@ -22,6 +22,8 @@ namespace Wasm { +class Module; + template using NativeIntegralType = Conditional>>>; @@ -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(1) << (sizeof(LocalIndex::Type) * 8 - 1); + ParseError with_eof_check(Stream const& stream, ParseError error_if_not_eof); template @@ -564,6 +568,8 @@ public: LocalIndex local_index() const { return m_local_index; } + void set_local_index(Badge, 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 parse(ConstrainedStream& stream, size_t size_hint); + auto total_local_count() const { return m_total_local_count; } + private: Vector 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 m_custom_sections; TypeSection m_type_section; diff --git a/Libraries/LibWasm/WASI/Wasi.cpp b/Libraries/LibWasm/WASI/Wasi.cpp index 6872728941..2ce479f010 100644 --- a/Libraries/LibWasm/WASI/Wasi.cpp +++ b/Libraries/LibWasm/WASI/Wasi.cpp @@ -994,7 +994,7 @@ struct InvocationOf { return_ty.append(ValueType(ValueType::I32)); return HostFunction( - [&self, function_name](Configuration& configuration, Vector& arguments) -> Wasm::Result { + [&self, function_name](Configuration& configuration, Span arguments) -> Wasm::Result { Tuple args = [&](IndexSequence) { return Tuple { ABI::deserialize(ABI::to_compatible_value(arguments[Is]))... }; }.template operator()(MakeIndexSequence()); @@ -1018,9 +1018,9 @@ struct InvocationOf { // Return values are passed as pointers, after the arguments if constexpr (requires { &R::serialize_into; }) { constexpr auto ResultCount = [](void (R::*)(Array) const) { return N; }(&R::serialize_into); - ABI::serialize(*value.result(), address_spans(arguments.span().slice(sizeof...(Args)), configuration)); + ABI::serialize(*value.result(), address_spans(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. diff --git a/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index f3538ef467..78aba9e2cf 100644 --- a/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -239,7 +239,7 @@ JS::ThrowCompletionOr> instantiate_module(JS // 3.2. If o is not an Object, throw a TypeError exception. if (!value.is_object()) - return vm.throw_completion(JS::ErrorType::NotAnObject, value); + return vm.throw_completion(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> 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 argument_values { vm.heap() }; size_t index = 0; for (auto& entry : arguments) { diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index e30407194c..dee25b4d70 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -140,7 +140,7 @@ private: static Optional 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 {} }; }, diff --git a/Utilities/wasm.cpp b/Utilities/wasm.cpp index 8c8122fc9b..d35d6e6c80 100644 --- a/Utilities/wasm.cpp +++ b/Utilities/wasm.cpp @@ -441,7 +441,7 @@ ErrorOr 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& args) mutable -> Wasm::Result { + [&vm, &function, formal_params, returns, name](Wasm::Configuration&, Span args) mutable -> Wasm::Result { Vector js_args; js_args.ensure_capacity(args.size()); for (size_t i = 0; i < formal_params.size(); ++i) { @@ -671,7 +671,7 @@ ErrorOr ladybird_main(Main::Arguments arguments) continue; auto type = parse_result->type_section().types()[entry.type.get().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;