diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 63dbfb9b45b..b1f3056906d 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -128,6 +128,7 @@ namespace JS::Bytecode { class alignas(void*) Instruction { public: constexpr static bool IsTerminator = false; + static constexpr bool IsVariableLength = false; enum class Type { #define __BYTECODE_OP(op) \ diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 92696c5314b..36c78ad9d81 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -330,10 +330,6 @@ Interpreter::HandleExceptionResponse Interpreter::handle_exception(size_t& progr VERIFY_NOT_REACHED(); } -#define NEXT_INSTRUCTION() \ - program_counter += instruction.length(); \ - goto start; - void Interpreter::run_bytecode(size_t entry_point) { auto& running_execution_context = vm().running_execution_context(); @@ -357,10 +353,12 @@ void Interpreter::run_bytecode(size_t entry_point) switch (instruction.type()) { case Instruction::Type::SetLocal: locals[static_cast(instruction).index()] = get(static_cast(instruction).src()); - NEXT_INSTRUCTION(); + program_counter += sizeof(Op::SetLocal); + goto start; case Instruction::Type::Mov: set(static_cast(instruction).dst(), get(static_cast(instruction).src())); - NEXT_INSTRUCTION(); + program_counter += sizeof(Op::Mov); + goto start; case Instruction::Type::End: accumulator = get(static_cast(instruction).value()); return; @@ -381,7 +379,8 @@ void Interpreter::run_bytecode(size_t entry_point) program_counter = jump.target().address(); goto start; } - NEXT_INSTRUCTION(); + program_counter += sizeof(Op::JumpTrue); + goto start; } case Instruction::Type::JumpFalse: { auto& jump = static_cast(instruction); @@ -389,7 +388,8 @@ void Interpreter::run_bytecode(size_t entry_point) program_counter = jump.target().address(); goto start; } - NEXT_INSTRUCTION(); + program_counter += sizeof(Op::JumpFalse); + goto start; } case Instruction::Type::JumpNullish: { auto& jump = static_cast(instruction); @@ -440,7 +440,121 @@ void Interpreter::run_bytecode(size_t entry_point) program_counter = finalizer.value(); goto start; } - default: + +#define HANDLE_INSTRUCTION(name) \ + case Instruction::Type::name: { \ + auto& typed_instruction = static_cast(instruction); \ + auto result = typed_instruction.execute_impl(*this); \ + if (result.is_error()) { \ + if (handle_exception(program_counter, *result.throw_completion().value()) == HandleExceptionResponse::ExitFromExecutable) \ + return; \ + goto start; \ + } \ + if constexpr (Op::name::IsVariableLength) \ + program_counter += instruction.length(); \ + else \ + program_counter += sizeof(Op::name); \ + goto start; \ + } + + HANDLE_INSTRUCTION(Add); + HANDLE_INSTRUCTION(ArrayAppend); + HANDLE_INSTRUCTION(AsyncIteratorClose); + HANDLE_INSTRUCTION(BitwiseAnd); + HANDLE_INSTRUCTION(BitwiseNot); + HANDLE_INSTRUCTION(BitwiseOr); + HANDLE_INSTRUCTION(BitwiseXor); + HANDLE_INSTRUCTION(BlockDeclarationInstantiation); + HANDLE_INSTRUCTION(Call); + HANDLE_INSTRUCTION(CallWithArgumentArray); + HANDLE_INSTRUCTION(Catch); + HANDLE_INSTRUCTION(ConcatString); + HANDLE_INSTRUCTION(CopyObjectExcludingProperties); + HANDLE_INSTRUCTION(CreateLexicalEnvironment); + HANDLE_INSTRUCTION(CreateVariable); + HANDLE_INSTRUCTION(Decrement); + HANDLE_INSTRUCTION(DeleteById); + HANDLE_INSTRUCTION(DeleteByIdWithThis); + HANDLE_INSTRUCTION(DeleteByValue); + HANDLE_INSTRUCTION(DeleteByValueWithThis); + HANDLE_INSTRUCTION(DeleteVariable); + HANDLE_INSTRUCTION(Div); + HANDLE_INSTRUCTION(Dump); + HANDLE_INSTRUCTION(EnterObjectEnvironment); + HANDLE_INSTRUCTION(Exp); + HANDLE_INSTRUCTION(GetById); + HANDLE_INSTRUCTION(GetByIdWithThis); + HANDLE_INSTRUCTION(GetByValue); + HANDLE_INSTRUCTION(GetByValueWithThis); + HANDLE_INSTRUCTION(GetCalleeAndThisFromEnvironment); + HANDLE_INSTRUCTION(GetGlobal); + HANDLE_INSTRUCTION(GetImportMeta); + HANDLE_INSTRUCTION(GetIterator); + HANDLE_INSTRUCTION(GetMethod); + HANDLE_INSTRUCTION(GetNewTarget); + HANDLE_INSTRUCTION(GetNextMethodFromIteratorRecord); + HANDLE_INSTRUCTION(GetObjectFromIteratorRecord); + HANDLE_INSTRUCTION(GetObjectPropertyIterator); + HANDLE_INSTRUCTION(GetPrivateById); + HANDLE_INSTRUCTION(GetVariable); + HANDLE_INSTRUCTION(GreaterThan); + HANDLE_INSTRUCTION(GreaterThanEquals); + HANDLE_INSTRUCTION(HasPrivateId); + HANDLE_INSTRUCTION(ImportCall); + HANDLE_INSTRUCTION(In); + HANDLE_INSTRUCTION(Increment); + HANDLE_INSTRUCTION(InstanceOf); + HANDLE_INSTRUCTION(IteratorClose); + HANDLE_INSTRUCTION(IteratorNext); + HANDLE_INSTRUCTION(IteratorToArray); + HANDLE_INSTRUCTION(LeaveFinally); + HANDLE_INSTRUCTION(LeaveLexicalEnvironment); + HANDLE_INSTRUCTION(LeaveUnwindContext); + HANDLE_INSTRUCTION(LeftShift); + HANDLE_INSTRUCTION(LessThan); + HANDLE_INSTRUCTION(LessThanEquals); + HANDLE_INSTRUCTION(LooselyEquals); + HANDLE_INSTRUCTION(LooselyInequals); + HANDLE_INSTRUCTION(Mod); + HANDLE_INSTRUCTION(Mul); + HANDLE_INSTRUCTION(NewArray); + HANDLE_INSTRUCTION(NewClass); + HANDLE_INSTRUCTION(NewFunction); + HANDLE_INSTRUCTION(NewObject); + HANDLE_INSTRUCTION(NewPrimitiveArray); + HANDLE_INSTRUCTION(NewRegExp); + HANDLE_INSTRUCTION(NewTypeError); + HANDLE_INSTRUCTION(Not); + HANDLE_INSTRUCTION(PostfixDecrement); + HANDLE_INSTRUCTION(PostfixIncrement); + HANDLE_INSTRUCTION(PutById); + HANDLE_INSTRUCTION(PutByIdWithThis); + HANDLE_INSTRUCTION(PutByValue); + HANDLE_INSTRUCTION(PutByValueWithThis); + HANDLE_INSTRUCTION(PutPrivateById); + HANDLE_INSTRUCTION(ResolveSuperBase); + HANDLE_INSTRUCTION(ResolveThisBinding); + HANDLE_INSTRUCTION(RestoreScheduledJump); + HANDLE_INSTRUCTION(RightShift); + HANDLE_INSTRUCTION(SetVariable); + HANDLE_INSTRUCTION(StrictlyEquals); + HANDLE_INSTRUCTION(StrictlyInequals); + HANDLE_INSTRUCTION(Sub); + HANDLE_INSTRUCTION(SuperCallWithArgumentArray); + HANDLE_INSTRUCTION(Throw); + HANDLE_INSTRUCTION(ThrowIfNotObject); + HANDLE_INSTRUCTION(ThrowIfNullish); + HANDLE_INSTRUCTION(ThrowIfTDZ); + HANDLE_INSTRUCTION(Typeof); + HANDLE_INSTRUCTION(TypeofVariable); + HANDLE_INSTRUCTION(UnaryMinus); + HANDLE_INSTRUCTION(UnaryPlus); + HANDLE_INSTRUCTION(UnsignedRightShift); + + case Instruction::Type::Await: + case Instruction::Type::Return: + case Instruction::Type::Yield: + // Handled delicately below. break; } @@ -466,7 +580,8 @@ void Interpreter::run_bytecode(size_t entry_point) break; } - NEXT_INSTRUCTION(); + program_counter += instruction.length(); + goto start; } if (!will_yield) { diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index e4a1d822336..337b9b03c9f 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -209,6 +209,8 @@ JS_ENUMERATE_NEW_BUILTIN_ERROR_OPS(JS_DECLARE_NEW_BUILTIN_ERROR_OP) // NOTE: This instruction is variable-width depending on the number of excluded names class CopyObjectExcludingProperties final : public Instruction { public: + static constexpr bool IsVariableLength = true; + CopyObjectExcludingProperties(Operand dst, Operand from_object, Vector const& excluded_names) : Instruction(Type::CopyObjectExcludingProperties, length_impl(excluded_names.size())) , m_dst(dst) @@ -242,6 +244,8 @@ private: // NOTE: This instruction is variable-width depending on the number of elements! class NewArray final : public Instruction { public: + static constexpr bool IsVariableLength = true; + explicit NewArray(Operand dst) : Instruction(Type::NewArray, length_impl(0)) , m_dst(dst) @@ -290,6 +294,8 @@ private: class NewPrimitiveArray final : public Instruction { public: + static constexpr bool IsVariableLength = true; + NewPrimitiveArray(Operand dst, ReadonlySpan elements) : Instruction(Type::NewPrimitiveArray, length_impl(elements.size())) , m_dst(dst) @@ -1230,6 +1236,8 @@ enum class CallType { class Call final : public Instruction { public: + static constexpr bool IsVariableLength = true; + Call(CallType type, Operand dst, Operand callee, Operand this_value, ReadonlySpan arguments, Optional expression_string = {}, Optional builtin = {}) : Instruction(Type::Call, length_impl(arguments.size())) , m_dst(dst)