|
@@ -342,233 +342,289 @@ void Interpreter::run_bytecode(size_t entry_point)
|
|
|
|
|
|
TemporaryChange change(m_program_counter, Optional<size_t&>(program_counter));
|
|
|
|
|
|
+ // Declare a lookup table for computed goto with each of the `handle_*` labels
|
|
|
+ // to avoid the overhead of a switch statement.
|
|
|
+ // This is a GCC extension, but it's also supported by Clang.
|
|
|
+
|
|
|
+ static void* const bytecode_dispatch_table[] = {
|
|
|
+#define SET_UP_LABEL(name) &&handle_##name,
|
|
|
+ ENUMERATE_BYTECODE_OPS(SET_UP_LABEL)
|
|
|
+ };
|
|
|
+
|
|
|
+#define DISPATCH_NEXT(name) \
|
|
|
+ do { \
|
|
|
+ if constexpr (Op::name::IsVariableLength) \
|
|
|
+ program_counter += instruction.length(); \
|
|
|
+ else \
|
|
|
+ program_counter += sizeof(Op::name); \
|
|
|
+ auto& next_instruction = *reinterpret_cast<Instruction const*>(&bytecode[program_counter]); \
|
|
|
+ goto* bytecode_dispatch_table[static_cast<size_t>(next_instruction.type())]; \
|
|
|
+ } while (0)
|
|
|
+
|
|
|
for (;;) {
|
|
|
start:
|
|
|
bool will_return = false;
|
|
|
bool will_yield = false;
|
|
|
|
|
|
for (;;) {
|
|
|
- auto& instruction = *reinterpret_cast<Instruction const*>(&bytecode[program_counter]);
|
|
|
+ goto* bytecode_dispatch_table[static_cast<size_t>((*reinterpret_cast<Instruction const*>(&bytecode[program_counter])).type())];
|
|
|
|
|
|
- switch (instruction.type()) {
|
|
|
- case Instruction::Type::SetLocal:
|
|
|
- locals[static_cast<Op::SetLocal const&>(instruction).index()] = get(static_cast<Op::SetLocal const&>(instruction).src());
|
|
|
- program_counter += sizeof(Op::SetLocal);
|
|
|
- goto start;
|
|
|
- case Instruction::Type::Mov:
|
|
|
- set(static_cast<Op::Mov const&>(instruction).dst(), get(static_cast<Op::Mov const&>(instruction).src()));
|
|
|
- program_counter += sizeof(Op::Mov);
|
|
|
- goto start;
|
|
|
- case Instruction::Type::End:
|
|
|
- accumulator = get(static_cast<Op::End const&>(instruction).value());
|
|
|
- return;
|
|
|
- case Instruction::Type::Jump:
|
|
|
- program_counter = static_cast<Op::Jump const&>(instruction).target().address();
|
|
|
- goto start;
|
|
|
- case Instruction::Type::JumpIf: {
|
|
|
- auto& jump = static_cast<Op::JumpIf const&>(instruction);
|
|
|
- if (get(jump.condition()).to_boolean())
|
|
|
- program_counter = jump.true_target().address();
|
|
|
- else
|
|
|
- program_counter = jump.false_target().address();
|
|
|
- goto start;
|
|
|
- }
|
|
|
- case Instruction::Type::JumpTrue: {
|
|
|
- auto& jump = static_cast<Op::JumpTrue const&>(instruction);
|
|
|
- if (get(jump.condition()).to_boolean()) {
|
|
|
- program_counter = jump.target().address();
|
|
|
- goto start;
|
|
|
- }
|
|
|
- program_counter += sizeof(Op::JumpTrue);
|
|
|
+ handle_SetLocal: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::SetLocal const*>(&bytecode[program_counter]);
|
|
|
+ locals[instruction.index()] = get(instruction.src());
|
|
|
+ DISPATCH_NEXT(SetLocal);
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_Mov: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::Mov const*>(&bytecode[program_counter]);
|
|
|
+ set(instruction.dst(), get(instruction.src()));
|
|
|
+ DISPATCH_NEXT(Mov);
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_End: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::End const*>(&bytecode[program_counter]);
|
|
|
+ accumulator = get(instruction.value());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_Jump: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::Jump const*>(&bytecode[program_counter]);
|
|
|
+ program_counter = instruction.target().address();
|
|
|
+ goto start;
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_JumpIf: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::JumpIf const*>(&bytecode[program_counter]);
|
|
|
+ if (get(instruction.condition()).to_boolean())
|
|
|
+ program_counter = instruction.true_target().address();
|
|
|
+ else
|
|
|
+ program_counter = instruction.false_target().address();
|
|
|
+ goto start;
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_JumpTrue: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::JumpTrue const*>(&bytecode[program_counter]);
|
|
|
+ if (get(instruction.condition()).to_boolean()) {
|
|
|
+ program_counter = instruction.target().address();
|
|
|
goto start;
|
|
|
}
|
|
|
- case Instruction::Type::JumpFalse: {
|
|
|
- auto& jump = static_cast<Op::JumpFalse const&>(instruction);
|
|
|
- if (!get(jump.condition()).to_boolean()) {
|
|
|
- program_counter = jump.target().address();
|
|
|
- goto start;
|
|
|
- }
|
|
|
- program_counter += sizeof(Op::JumpFalse);
|
|
|
+ DISPATCH_NEXT(JumpTrue);
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_JumpFalse: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::JumpFalse const*>(&bytecode[program_counter]);
|
|
|
+ if (!get(instruction.condition()).to_boolean()) {
|
|
|
+ program_counter = instruction.target().address();
|
|
|
goto start;
|
|
|
}
|
|
|
- case Instruction::Type::JumpNullish: {
|
|
|
- auto& jump = static_cast<Op::JumpNullish const&>(instruction);
|
|
|
- if (get(jump.condition()).is_nullish())
|
|
|
- program_counter = jump.true_target().address();
|
|
|
- else
|
|
|
- program_counter = jump.false_target().address();
|
|
|
+ DISPATCH_NEXT(JumpFalse);
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_JumpNullish: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::JumpNullish const*>(&bytecode[program_counter]);
|
|
|
+ if (get(instruction.condition()).is_nullish())
|
|
|
+ program_counter = instruction.true_target().address();
|
|
|
+ else
|
|
|
+ program_counter = instruction.false_target().address();
|
|
|
+ goto start;
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_JumpUndefined: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::JumpUndefined const*>(&bytecode[program_counter]);
|
|
|
+ if (get(instruction.condition()).is_undefined())
|
|
|
+ program_counter = instruction.true_target().address();
|
|
|
+ else
|
|
|
+ program_counter = instruction.false_target().address();
|
|
|
+ goto start;
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_EnterUnwindContext: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::EnterUnwindContext const*>(&bytecode[program_counter]);
|
|
|
+ enter_unwind_context();
|
|
|
+ program_counter = instruction.entry_point().address();
|
|
|
+ goto start;
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_ContinuePendingUnwind: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::ContinuePendingUnwind const*>(&bytecode[program_counter]);
|
|
|
+ if (auto exception = reg(Register::exception()); !exception.is_empty()) {
|
|
|
+ if (handle_exception(program_counter, exception) == HandleExceptionResponse::ExitFromExecutable)
|
|
|
+ return;
|
|
|
goto start;
|
|
|
}
|
|
|
- case Instruction::Type::JumpUndefined: {
|
|
|
- auto& jump = static_cast<Op::JumpUndefined const&>(instruction);
|
|
|
- if (get(jump.condition()).is_undefined())
|
|
|
- program_counter = jump.true_target().address();
|
|
|
- else
|
|
|
- program_counter = jump.false_target().address();
|
|
|
- goto start;
|
|
|
+ if (!saved_return_value().is_empty()) {
|
|
|
+ do_return(saved_return_value());
|
|
|
+ goto may_return;
|
|
|
}
|
|
|
- case Instruction::Type::EnterUnwindContext:
|
|
|
- enter_unwind_context();
|
|
|
- program_counter = static_cast<Op::EnterUnwindContext const&>(instruction).entry_point().address();
|
|
|
- goto start;
|
|
|
- case Instruction::Type::ContinuePendingUnwind: {
|
|
|
- if (auto exception = reg(Register::exception()); !exception.is_empty()) {
|
|
|
- if (handle_exception(program_counter, exception) == HandleExceptionResponse::ExitFromExecutable)
|
|
|
- return;
|
|
|
- goto start;
|
|
|
- }
|
|
|
- if (!saved_return_value().is_empty()) {
|
|
|
- do_return(saved_return_value());
|
|
|
- goto may_return;
|
|
|
- }
|
|
|
- auto const old_scheduled_jump = running_execution_context.previously_scheduled_jumps.take_last();
|
|
|
- if (m_scheduled_jump.has_value()) {
|
|
|
- program_counter = m_scheduled_jump.value();
|
|
|
- m_scheduled_jump = {};
|
|
|
- } else {
|
|
|
- program_counter = static_cast<Op::ContinuePendingUnwind const&>(instruction).resume_target().address();
|
|
|
- // set the scheduled jump to the old value if we continue
|
|
|
- // where we left it
|
|
|
- m_scheduled_jump = old_scheduled_jump;
|
|
|
- }
|
|
|
- goto start;
|
|
|
+ auto const old_scheduled_jump = running_execution_context.previously_scheduled_jumps.take_last();
|
|
|
+ if (m_scheduled_jump.has_value()) {
|
|
|
+ program_counter = m_scheduled_jump.value();
|
|
|
+ m_scheduled_jump = {};
|
|
|
+ } else {
|
|
|
+ program_counter = instruction.resume_target().address();
|
|
|
+ // set the scheduled jump to the old value if we continue
|
|
|
+ // where we left it
|
|
|
+ m_scheduled_jump = old_scheduled_jump;
|
|
|
}
|
|
|
- case Instruction::Type::ScheduleJump: {
|
|
|
- m_scheduled_jump = static_cast<Op::ScheduleJump const&>(instruction).target().address();
|
|
|
- auto finalizer = executable.exception_handlers_for_offset(program_counter).value().finalizer_offset;
|
|
|
- VERIFY(finalizer.has_value());
|
|
|
- program_counter = finalizer.value();
|
|
|
+ goto start;
|
|
|
+ }
|
|
|
+
|
|
|
+ handle_ScheduleJump: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::ScheduleJump const*>(&bytecode[program_counter]);
|
|
|
+ m_scheduled_jump = instruction.target().address();
|
|
|
+ auto finalizer = executable.exception_handlers_for_offset(program_counter).value().finalizer_offset;
|
|
|
+ VERIFY(finalizer.has_value());
|
|
|
+ program_counter = finalizer.value();
|
|
|
+ goto start;
|
|
|
+ }
|
|
|
+
|
|
|
+#define HANDLE_INSTRUCTION(name) \
|
|
|
+ handle_##name: \
|
|
|
+ { \
|
|
|
+ auto& instruction = *reinterpret_cast<Op::name const*>(&bytecode[program_counter]); \
|
|
|
+ { \
|
|
|
+ auto result = instruction.execute_impl(*this); \
|
|
|
+ if (result.is_error()) { \
|
|
|
+ if (handle_exception(program_counter, *result.throw_completion().value()) == HandleExceptionResponse::ExitFromExecutable) \
|
|
|
+ return; \
|
|
|
+ goto start; \
|
|
|
+ } \
|
|
|
+ } \
|
|
|
+ DISPATCH_NEXT(name); \
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ handle_Await: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::Await const*>(&bytecode[program_counter]);
|
|
|
+ auto result = instruction.execute(*this);
|
|
|
+
|
|
|
+ if (result.is_error()) {
|
|
|
+ if (handle_exception(program_counter, *result.throw_completion().value()) == HandleExceptionResponse::ExitFromExecutable)
|
|
|
+ return;
|
|
|
goto start;
|
|
|
}
|
|
|
+ goto may_return;
|
|
|
+ }
|
|
|
|
|
|
-#define HANDLE_INSTRUCTION(name) \
|
|
|
- case Instruction::Type::name: { \
|
|
|
- auto& typed_instruction = static_cast<Op::name const&>(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_Return: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::Return const*>(&bytecode[program_counter]);
|
|
|
+ auto result = instruction.execute(*this);
|
|
|
|
|
|
- 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;
|
|
|
+ if (result.is_error()) {
|
|
|
+ if (handle_exception(program_counter, *result.throw_completion().value()) == HandleExceptionResponse::ExitFromExecutable)
|
|
|
+ return;
|
|
|
+ goto start;
|
|
|
}
|
|
|
+ goto may_return;
|
|
|
+ }
|
|
|
|
|
|
- {
|
|
|
- auto result = instruction.execute(*this);
|
|
|
+ handle_Yield: {
|
|
|
+ auto& instruction = *reinterpret_cast<Op::Yield const*>(&bytecode[program_counter]);
|
|
|
+ auto result = instruction.execute(*this);
|
|
|
|
|
|
- if (result.is_error()) {
|
|
|
- if (handle_exception(program_counter, *result.throw_completion().value()) == HandleExceptionResponse::ExitFromExecutable)
|
|
|
- return;
|
|
|
- goto start;
|
|
|
- }
|
|
|
+ if (result.is_error()) {
|
|
|
+ if (handle_exception(program_counter, *result.throw_completion().value()) == HandleExceptionResponse::ExitFromExecutable)
|
|
|
+ return;
|
|
|
+ goto start;
|
|
|
}
|
|
|
+ goto may_return;
|
|
|
+ }
|
|
|
|
|
|
- may_return:
|
|
|
+ may_return: {
|
|
|
+ auto& instruction = *reinterpret_cast<Instruction const*>(&bytecode[program_counter]);
|
|
|
if (!reg(Register::return_value()).is_empty()) {
|
|
|
will_return = true;
|
|
|
// Note: A `yield` statement will not go through a finally statement,
|
|
@@ -583,6 +639,7 @@ void Interpreter::run_bytecode(size_t entry_point)
|
|
|
program_counter += instruction.length();
|
|
|
goto start;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
if (!will_yield) {
|
|
|
if (auto handlers = executable.exception_handlers_for_offset(program_counter); handlers.has_value()) {
|