2021-06-03 10:46:30 +02:00
/*
2024-01-27 20:51:11 +01:00
* Copyright ( c ) 2021 - 2024 , Andreas Kling < kling @ serenityos . org >
2021-06-03 10:46:30 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2021-06-07 15:17:37 +02:00
# include <AK/Debug.h>
2023-09-27 10:10:00 +02:00
# include <AK/HashTable.h>
2021-06-09 10:02:01 +02:00
# include <AK/TemporaryChange.h>
2023-06-15 12:36:57 +02:00
# include <LibJS/AST.h>
2021-06-09 06:49:58 +04:30
# include <LibJS/Bytecode/BasicBlock.h>
2023-10-18 13:26:47 +02:00
# include <LibJS/Bytecode/CommonImplementations.h>
2023-06-17 13:16:35 +02:00
# include <LibJS/Bytecode/Generator.h>
2021-06-03 10:46:30 +02:00
# include <LibJS/Bytecode/Instruction.h>
# include <LibJS/Bytecode/Interpreter.h>
2023-10-20 00:33:51 +02:00
# include <LibJS/Bytecode/Label.h>
2021-06-09 09:19:34 +02:00
# include <LibJS/Bytecode/Op.h>
2023-09-27 10:10:00 +02:00
# include <LibJS/Runtime/AbstractOperations.h>
# include <LibJS/Runtime/Array.h>
# include <LibJS/Runtime/BigInt.h>
# include <LibJS/Runtime/DeclarativeEnvironment.h>
# include <LibJS/Runtime/ECMAScriptFunctionObject.h>
# include <LibJS/Runtime/Environment.h>
# include <LibJS/Runtime/FunctionEnvironment.h>
2021-07-01 12:24:46 +02:00
# include <LibJS/Runtime/GlobalEnvironment.h>
2021-06-03 18:26:13 +02:00
# include <LibJS/Runtime/GlobalObject.h>
2023-09-27 10:10:00 +02:00
# include <LibJS/Runtime/Iterator.h>
2023-11-30 19:49:29 +01:00
# include <LibJS/Runtime/MathObject.h>
2023-09-27 10:10:00 +02:00
# include <LibJS/Runtime/NativeFunction.h>
# include <LibJS/Runtime/ObjectEnvironment.h>
2021-09-11 20:27:36 +01:00
# include <LibJS/Runtime/Realm.h>
2023-09-27 10:10:00 +02:00
# include <LibJS/Runtime/Reference.h>
# include <LibJS/Runtime/RegExpObject.h>
# include <LibJS/Runtime/Value.h>
2023-10-06 17:54:21 +02:00
# include <LibJS/Runtime/ValueInlines.h>
2023-09-27 10:10:00 +02:00
# include <LibJS/SourceTextModule.h>
2021-06-03 10:46:30 +02:00
namespace JS : : Bytecode {
2021-10-24 13:34:46 +02:00
bool g_dump_bytecode = false ;
2021-06-05 15:53:36 +02:00
2024-02-04 08:00:54 +01:00
static ByteString format_operand ( StringView name , Operand operand , Bytecode : : Executable const & executable )
{
StringBuilder builder ;
2024-02-20 15:59:45 +01:00
if ( ! name . is_empty ( ) )
builder . appendff ( " \033 [32m{} \033 [0m: " , name ) ;
2024-02-04 08:00:54 +01:00
switch ( operand . type ( ) ) {
case Operand : : Type : : Register :
builder . appendff ( " \033 [33mreg{} \033 [0m " , operand . index ( ) ) ;
break ;
case Operand : : Type : : Local :
// FIXME: Show local name.
builder . appendff ( " \033 [34mloc{} \033 [0m " , operand . index ( ) ) ;
break ;
case Operand : : Type : : Constant : {
builder . append ( " \033 [36m " sv ) ;
auto value = executable . constants [ operand . index ( ) ] ;
if ( value . is_empty ( ) )
builder . append ( " <Empty> " sv ) ;
else if ( value . is_boolean ( ) )
builder . appendff ( " Bool({}) " , value . as_bool ( ) ? " true " sv : " false " sv ) ;
else if ( value . is_int32 ( ) )
builder . appendff ( " Int32({}) " , value . as_i32 ( ) ) ;
else if ( value . is_double ( ) )
builder . appendff ( " Double({}) " , value . as_double ( ) ) ;
2024-03-03 11:40:00 +01:00
else if ( value . is_bigint ( ) )
builder . appendff ( " BigInt({}) " , value . as_bigint ( ) . to_byte_string ( ) ) ;
2024-03-03 11:34:36 +01:00
else if ( value . is_string ( ) )
builder . appendff ( " String( \" {} \" ) " , value . as_string ( ) . utf8_string_view ( ) ) ;
2024-02-04 08:00:54 +01:00
else if ( value . is_undefined ( ) )
builder . append ( " Undefined " sv ) ;
else if ( value . is_null ( ) )
builder . append ( " Null " sv ) ;
else
builder . appendff ( " Value: {} " , value ) ;
builder . append ( " \033 [0m " sv ) ;
break ;
}
default :
VERIFY_NOT_REACHED ( ) ;
}
return builder . to_byte_string ( ) ;
}
2024-02-20 15:59:45 +01:00
static ByteString format_operand_list ( StringView name , ReadonlySpan < Operand > operands , Bytecode : : Executable const & executable )
{
StringBuilder builder ;
if ( ! name . is_empty ( ) )
2024-02-27 07:43:35 +01:00
builder . appendff ( " , \033 [32m{} \033 [0m:[ " , name ) ;
2024-02-20 15:59:45 +01:00
for ( size_t i = 0 ; i < operands . size ( ) ; + + i ) {
if ( i ! = 0 )
builder . append ( " , " sv ) ;
builder . appendff ( " {} " , format_operand ( " " sv , operands [ i ] , executable ) ) ;
}
builder . append ( " ] " sv ) ;
return builder . to_byte_string ( ) ;
}
2024-03-03 12:37:28 +01:00
static ByteString format_value_list ( StringView name , ReadonlySpan < Value > values )
{
StringBuilder builder ;
if ( ! name . is_empty ( ) )
builder . appendff ( " , \033 [32m{} \033 [0m:[ " , name ) ;
builder . join ( " , " sv , values ) ;
builder . append ( " ] " sv ) ;
return builder . to_byte_string ( ) ;
}
2024-03-04 09:34:30 +01:00
ALWAYS_INLINE static ThrowCompletionOr < Value > loosely_inequals ( VM & vm , Value src1 , Value src2 )
2024-03-03 14:56:33 +01:00
{
2024-03-04 09:34:30 +01:00
if ( src1 . tag ( ) = = src2 . tag ( ) ) {
if ( src1 . is_int32 ( ) | | src1 . is_object ( ) | | src1 . is_boolean ( ) | | src1 . is_nullish ( ) )
return Value ( src1 . encoded ( ) ! = src2 . encoded ( ) ) ;
}
2024-03-03 14:56:33 +01:00
return Value ( ! TRY ( is_loosely_equal ( vm , src1 , src2 ) ) ) ;
}
2024-03-04 09:34:30 +01:00
ALWAYS_INLINE static ThrowCompletionOr < Value > loosely_equals ( VM & vm , Value src1 , Value src2 )
2024-03-03 14:56:33 +01:00
{
2024-03-04 09:34:30 +01:00
if ( src1 . tag ( ) = = src2 . tag ( ) ) {
if ( src1 . is_int32 ( ) | | src1 . is_object ( ) | | src1 . is_boolean ( ) | | src1 . is_nullish ( ) )
return Value ( src1 . encoded ( ) = = src2 . encoded ( ) ) ;
}
2024-03-03 14:56:33 +01:00
return Value ( TRY ( is_loosely_equal ( vm , src1 , src2 ) ) ) ;
}
2024-03-04 09:34:30 +01:00
ALWAYS_INLINE static ThrowCompletionOr < Value > strict_inequals ( VM & , Value src1 , Value src2 )
2024-03-03 14:56:33 +01:00
{
2024-03-04 09:34:30 +01:00
if ( src1 . tag ( ) = = src2 . tag ( ) ) {
if ( src1 . is_int32 ( ) | | src1 . is_object ( ) | | src1 . is_boolean ( ) | | src1 . is_nullish ( ) )
return Value ( src1 . encoded ( ) ! = src2 . encoded ( ) ) ;
}
2024-03-03 14:56:33 +01:00
return Value ( ! is_strictly_equal ( src1 , src2 ) ) ;
}
2024-03-04 09:34:30 +01:00
ALWAYS_INLINE static ThrowCompletionOr < Value > strict_equals ( VM & , Value src1 , Value src2 )
2024-03-03 14:56:33 +01:00
{
2024-03-04 09:34:30 +01:00
if ( src1 . tag ( ) = = src2 . tag ( ) ) {
if ( src1 . is_int32 ( ) | | src1 . is_object ( ) | | src1 . is_boolean ( ) | | src1 . is_nullish ( ) )
return Value ( src1 . encoded ( ) = = src2 . encoded ( ) ) ;
}
2024-03-03 14:56:33 +01:00
return Value ( is_strictly_equal ( src1 , src2 ) ) ;
}
2023-06-22 15:59:18 +02:00
Interpreter : : Interpreter ( VM & vm )
: m_vm ( vm )
2021-06-05 15:53:36 +02:00
{
2021-06-03 10:46:30 +02:00
}
Interpreter : : ~ Interpreter ( )
{
}
2024-02-04 08:00:54 +01:00
ALWAYS_INLINE Value Interpreter : : get ( Operand op ) const
2024-02-02 10:19:17 +01:00
{
switch ( op . type ( ) ) {
case Operand : : Type : : Register :
return reg ( Register { op . index ( ) } ) ;
case Operand : : Type : : Local :
return vm ( ) . running_execution_context ( ) . locals [ op . index ( ) ] ;
case Operand : : Type : : Constant :
return current_executable ( ) . constants [ op . index ( ) ] ;
}
2024-02-04 08:00:54 +01:00
__builtin_unreachable ( ) ;
2024-02-02 10:19:17 +01:00
}
2024-02-04 08:00:54 +01:00
ALWAYS_INLINE void Interpreter : : set ( Operand op , Value value )
2024-02-02 10:19:17 +01:00
{
switch ( op . type ( ) ) {
case Operand : : Type : : Register :
reg ( Register { op . index ( ) } ) = value ;
return ;
case Operand : : Type : : Local :
vm ( ) . running_execution_context ( ) . locals [ op . index ( ) ] = value ;
return ;
case Operand : : Type : : Constant :
VERIFY_NOT_REACHED ( ) ;
}
2024-02-04 08:00:54 +01:00
__builtin_unreachable ( ) ;
2024-02-02 10:19:17 +01:00
}
2023-06-15 12:36:57 +02:00
// 16.1.6 ScriptEvaluation ( scriptRecord ), https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation
ThrowCompletionOr < Value > Interpreter : : run ( Script & script_record , JS : : GCPtr < Environment > lexical_environment_override )
{
auto & vm = this - > vm ( ) ;
// 1. Let globalEnv be scriptRecord.[[Realm]].[[GlobalEnv]].
auto & global_environment = script_record . realm ( ) . global_environment ( ) ;
// 2. Let scriptContext be a new ECMAScript code execution context.
2023-11-27 16:45:45 +01:00
auto script_context = ExecutionContext : : create ( vm . heap ( ) ) ;
2023-06-15 12:36:57 +02:00
// 3. Set the Function of scriptContext to null.
// NOTE: This was done during execution context construction.
// 4. Set the Realm of scriptContext to scriptRecord.[[Realm]].
2023-11-27 16:45:45 +01:00
script_context - > realm = & script_record . realm ( ) ;
2023-06-15 12:36:57 +02:00
// 5. Set the ScriptOrModule of scriptContext to scriptRecord.
2023-11-27 16:45:45 +01:00
script_context - > script_or_module = NonnullGCPtr < Script > ( script_record ) ;
2023-06-15 12:36:57 +02:00
// 6. Set the VariableEnvironment of scriptContext to globalEnv.
2023-11-27 16:45:45 +01:00
script_context - > variable_environment = & global_environment ;
2023-06-15 12:36:57 +02:00
// 7. Set the LexicalEnvironment of scriptContext to globalEnv.
2023-11-27 16:45:45 +01:00
script_context - > lexical_environment = & global_environment ;
2023-06-15 12:36:57 +02:00
// Non-standard: Override the lexical environment if requested.
if ( lexical_environment_override )
2023-11-27 16:45:45 +01:00
script_context - > lexical_environment = lexical_environment_override ;
2023-06-15 12:36:57 +02:00
// 8. Set the PrivateEnvironment of scriptContext to null.
// NOTE: This isn't in the spec, but we require it.
2023-11-27 16:45:45 +01:00
script_context - > is_strict_mode = script_record . parse_node ( ) . is_strict_mode ( ) ;
2023-06-15 12:36:57 +02:00
// FIXME: 9. Suspend the currently running execution context.
// 10. Push scriptContext onto the execution context stack; scriptContext is now the running execution context.
2023-11-27 16:45:45 +01:00
TRY ( vm . push_execution_context ( * script_context , { } ) ) ;
2023-06-15 12:36:57 +02:00
// 11. Let script be scriptRecord.[[ECMAScriptCode]].
auto & script = script_record . parse_node ( ) ;
// 12. Let result be Completion(GlobalDeclarationInstantiation(script, globalEnv)).
auto instantiation_result = script . global_declaration_instantiation ( vm , global_environment ) ;
Completion result = instantiation_result . is_throw_completion ( ) ? instantiation_result . throw_completion ( ) : normal_completion ( { } ) ;
// 13. If result.[[Type]] is normal, then
if ( result . type ( ) = = Completion : : Type : : Normal ) {
2024-02-04 08:00:54 +01:00
auto executable_result = JS : : Bytecode : : Generator : : generate ( vm , script , { } ) ;
2023-06-15 12:36:57 +02:00
if ( executable_result . is_error ( ) ) {
if ( auto error_string = executable_result . error ( ) . to_string ( ) ; error_string . is_error ( ) )
result = vm . template throw_completion < JS : : InternalError > ( vm . error_message ( JS : : VM : : ErrorMessage : : OutOfMemory ) ) ;
else if ( error_string = String : : formatted ( " TODO({}) " , error_string.value()) ; error_string . is_error ( ) )
result = vm . template throw_completion < JS : : InternalError > ( vm . error_message ( JS : : VM : : ErrorMessage : : OutOfMemory ) ) ;
else
result = JS : : throw_completion ( JS : : InternalError : : create ( realm ( ) , error_string . release_value ( ) ) ) ;
} else {
auto executable = executable_result . release_value ( ) ;
if ( g_dump_bytecode )
executable - > dump ( ) ;
// a. Set result to the result of evaluating script.
2024-05-01 19:33:49 +02:00
auto result_or_error = run_executable ( * executable , nullptr ) ;
2023-06-15 12:36:57 +02:00
if ( result_or_error . value . is_error ( ) )
result = result_or_error . value . release_error ( ) ;
else
2024-05-01 19:33:49 +02:00
result = result_or_error . return_register_value ;
2023-06-15 12:36:57 +02:00
}
}
// 14. If result.[[Type]] is normal and result.[[Value]] is empty, then
if ( result . type ( ) = = Completion : : Type : : Normal & & ! result . value ( ) . has_value ( ) ) {
// a. Set result to NormalCompletion(undefined).
result = normal_completion ( js_undefined ( ) ) ;
}
// FIXME: 15. Suspend scriptContext and remove it from the execution context stack.
vm . pop_execution_context ( ) ;
// 16. Assert: The execution context stack is not empty.
VERIFY ( ! vm . execution_context_stack ( ) . is_empty ( ) ) ;
// FIXME: 17. Resume the context that is now on the top of the execution context stack as the running execution context.
// At this point we may have already run any queued promise jobs via on_call_stack_emptied,
// in which case this is a no-op.
// FIXME: These three should be moved out of Interpreter::run and give the host an option to run these, as it's up to the host when these get run.
// https://tc39.es/ecma262/#sec-jobs for jobs and https://tc39.es/ecma262/#_ref_3508 for ClearKeptObjects
// finish_execution_generation is particularly an issue for LibWeb, as the HTML spec wants to run it specifically after performing a microtask checkpoint.
// The promise and registry cleanup queues don't cause LibWeb an issue, as LibWeb overrides the hooks that push onto these queues.
vm . run_queued_promise_jobs ( ) ;
vm . run_queued_finalization_registry_cleanup_jobs ( ) ;
vm . finish_execution_generation ( ) ;
// 18. Return ? result.
if ( result . is_abrupt ( ) ) {
VERIFY ( result . type ( ) = = Completion : : Type : : Throw ) ;
return result . release_error ( ) ;
}
VERIFY ( result . value ( ) . has_value ( ) ) ;
return * result . value ( ) ;
}
ThrowCompletionOr < Value > Interpreter : : run ( SourceTextModule & module )
{
// FIXME: This is not a entry point as defined in the spec, but is convenient.
// To avoid work we use link_and_eval_module however that can already be
// dangerous if the vm loaded other modules.
auto & vm = this - > vm ( ) ;
TRY ( vm . link_and_eval_module ( Badge < Bytecode : : Interpreter > { } , module ) ) ;
vm . run_queued_promise_jobs ( ) ;
vm . run_queued_finalization_registry_cleanup_jobs ( ) ;
return js_undefined ( ) ;
}
2024-02-20 14:08:33 -05:00
void Interpreter : : run_bytecode ( )
2021-06-03 10:46:30 +02:00
{
2023-11-27 16:45:45 +01:00
auto * locals = vm ( ) . running_execution_context ( ) . locals . data ( ) ;
2023-09-27 10:31:07 +02:00
auto & accumulator = this - > accumulator ( ) ;
2021-06-09 06:49:58 +04:30
for ( ; ; ) {
2023-09-26 16:45:55 +02:00
start :
2023-09-01 16:53:55 +02:00
auto pc = InstructionStreamIterator { m_current_block - > instruction_stream ( ) , m_current_executable } ;
TemporaryChange temp_change { m_pc , Optional < InstructionStreamIterator & > ( pc ) } ;
2022-10-30 11:58:46 +01:00
2021-06-09 06:49:58 +04:30
bool will_return = false ;
2022-12-06 20:45:38 +01:00
bool will_yield = false ;
2023-09-26 16:41:42 +02:00
2023-09-26 19:43:44 +02:00
ThrowCompletionOr < void > result ;
2021-06-09 06:49:58 +04:30
while ( ! pc . at_end ( ) ) {
auto & instruction = * pc ;
2023-09-26 17:14:59 +02:00
2023-09-26 19:43:44 +02:00
switch ( instruction . type ( ) ) {
2023-09-27 10:31:07 +02:00
case Instruction : : Type : : SetLocal :
2024-02-04 08:00:54 +01:00
locals [ static_cast < Op : : SetLocal const & > ( instruction ) . index ( ) ] = get ( static_cast < Op : : SetLocal const & > ( instruction ) . src ( ) ) ;
2023-09-27 10:31:07 +02:00
break ;
2024-02-04 08:00:54 +01:00
case Instruction : : Type : : Mov :
set ( static_cast < Op : : Mov const & > ( instruction ) . dst ( ) , get ( static_cast < Op : : Mov const & > ( instruction ) . src ( ) ) ) ;
2023-09-27 10:31:07 +02:00
break ;
2024-02-04 08:00:54 +01:00
case Instruction : : Type : : End :
accumulator = get ( static_cast < Op : : End const & > ( instruction ) . value ( ) ) ;
return ;
2023-09-26 19:43:44 +02:00
case Instruction : : Type : : Jump :
m_current_block = & static_cast < Op : : Jump const & > ( instruction ) . true_target ( ) - > block ( ) ;
goto start ;
2024-02-04 08:00:54 +01:00
case Instruction : : Type : : JumpIf :
if ( get ( static_cast < Op : : JumpIf const & > ( instruction ) . condition ( ) ) . to_boolean ( ) )
m_current_block = & static_cast < Op : : JumpIf const & > ( instruction ) . true_target ( ) - > block ( ) ;
2023-09-26 19:43:44 +02:00
else
2024-02-04 08:00:54 +01:00
m_current_block = & static_cast < Op : : JumpIf const & > ( instruction ) . false_target ( ) - > block ( ) ;
2023-09-26 19:43:44 +02:00
goto start ;
case Instruction : : Type : : JumpNullish :
2024-02-04 08:00:54 +01:00
if ( get ( static_cast < Op : : JumpNullish const & > ( instruction ) . condition ( ) ) . is_nullish ( ) )
2023-09-26 19:43:44 +02:00
m_current_block = & static_cast < Op : : Jump const & > ( instruction ) . true_target ( ) - > block ( ) ;
else
m_current_block = & static_cast < Op : : Jump const & > ( instruction ) . false_target ( ) - > block ( ) ;
goto start ;
case Instruction : : Type : : JumpUndefined :
2024-02-04 08:00:54 +01:00
if ( get ( static_cast < Op : : JumpUndefined const & > ( instruction ) . condition ( ) ) . is_undefined ( ) )
2023-09-26 19:43:44 +02:00
m_current_block = & static_cast < Op : : Jump const & > ( instruction ) . true_target ( ) - > block ( ) ;
else
m_current_block = & static_cast < Op : : Jump const & > ( instruction ) . false_target ( ) - > block ( ) ;
goto start ;
case Instruction : : Type : : EnterUnwindContext :
2023-10-20 00:33:51 +02:00
enter_unwind_context ( ) ;
2023-09-26 19:43:44 +02:00
m_current_block = & static_cast < Op : : EnterUnwindContext const & > ( instruction ) . entry_point ( ) . block ( ) ;
goto start ;
2023-10-21 22:46:40 +02:00
case Instruction : : Type : : ContinuePendingUnwind : {
2023-09-26 19:43:44 +02:00
if ( auto exception = reg ( Register : : exception ( ) ) ; ! exception . is_empty ( ) ) {
result = throw_completion ( exception ) ;
break ;
}
if ( ! saved_return_value ( ) . is_empty ( ) ) {
do_return ( saved_return_value ( ) ) ;
break ;
}
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm ( ) . running_execution_context ( ) ;
auto const * old_scheduled_jump = running_execution_context . previously_scheduled_jumps . take_last ( ) ;
2023-09-26 19:43:44 +02:00
if ( m_scheduled_jump ) {
m_current_block = exchange ( m_scheduled_jump , nullptr ) ;
} else {
m_current_block = & static_cast < Op : : ContinuePendingUnwind const & > ( instruction ) . resume_target ( ) . block ( ) ;
2023-10-21 22:46:40 +02:00
// set the scheduled jump to the old value if we continue
// where we left it
m_scheduled_jump = old_scheduled_jump ;
2023-09-26 19:43:44 +02:00
}
goto start ;
2023-10-21 22:46:40 +02:00
}
2023-10-20 00:33:51 +02:00
case Instruction : : Type : : ScheduleJump : {
2023-09-26 19:43:44 +02:00
m_scheduled_jump = & static_cast < Op : : ScheduleJump const & > ( instruction ) . target ( ) . block ( ) ;
2023-10-20 00:33:51 +02:00
auto const * finalizer = m_current_block - > finalizer ( ) ;
VERIFY ( finalizer ) ;
m_current_block = finalizer ;
2023-09-26 19:43:44 +02:00
goto start ;
2023-10-20 00:33:51 +02:00
}
2023-09-26 19:43:44 +02:00
default :
result = instruction . execute ( * this ) ;
break ;
}
if ( result . is_error ( ) ) [[unlikely]] {
reg ( Register : : exception ( ) ) = * result . throw_completion ( ) . value ( ) ;
2023-10-20 17:55:14 +02:00
m_scheduled_jump = { } ;
2023-10-20 00:33:51 +02:00
auto const * handler = m_current_block - > handler ( ) ;
auto const * finalizer = m_current_block - > finalizer ( ) ;
if ( ! handler & & ! finalizer )
2023-09-26 17:14:59 +02:00
return ;
2023-10-20 00:33:51 +02:00
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm ( ) . running_execution_context ( ) ;
auto & unwind_context = running_execution_context . unwind_contexts . last ( ) ;
2023-10-20 00:33:51 +02:00
VERIFY ( unwind_context . executable = = m_current_executable ) ;
if ( handler ) {
m_current_block = handler ;
2023-09-26 16:45:55 +02:00
goto start ;
2021-10-24 23:52:39 +02:00
}
2023-10-20 00:33:51 +02:00
if ( finalizer ) {
m_current_block = finalizer ;
2023-09-26 16:45:55 +02:00
goto start ;
2021-06-10 15:04:38 +02:00
}
2022-03-14 02:20:50 +00:00
// An unwind context with no handler or finalizer? We have nowhere to jump, and continuing on will make us crash on the next `Call` to a non-native function if there's an exception! So let's crash here instead.
// If you run into this, you probably forgot to remove the current unwind_context somewhere.
VERIFY_NOT_REACHED ( ) ;
2021-06-10 15:04:38 +02:00
}
2023-09-26 19:43:44 +02:00
2023-09-26 15:32:46 +02:00
if ( ! reg ( Register : : return_value ( ) ) . is_empty ( ) ) {
2021-06-09 06:49:58 +04:30
will_return = true ;
2022-12-06 20:45:38 +01:00
// Note: A `yield` statement will not go through a finally statement,
// hence we need to set a flag to not do so,
// but we generate a Yield Operation in the case of returns in
// generators as well, so we need to check if it will actually
// continue or is a `return` in disguise
2023-07-15 09:59:19 +02:00
will_yield = ( instruction . type ( ) = = Instruction : : Type : : Yield & & static_cast < Op : : Yield const & > ( instruction ) . continuation ( ) . has_value ( ) ) | | instruction . type ( ) = = Instruction : : Type : : Await ;
2021-06-09 06:49:58 +04:30
break ;
}
+ + pc ;
2021-06-04 12:07:38 +02:00
}
2021-06-09 06:49:58 +04:30
2023-10-20 00:33:51 +02:00
if ( auto const * finalizer = m_current_block - > finalizer ( ) ; finalizer & & ! will_yield ) {
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm ( ) . running_execution_context ( ) ;
auto & unwind_context = running_execution_context . unwind_contexts . last ( ) ;
2023-10-20 00:33:51 +02:00
VERIFY ( unwind_context . executable = = m_current_executable ) ;
reg ( Register : : saved_return_value ( ) ) = reg ( Register : : return_value ( ) ) ;
reg ( Register : : return_value ( ) ) = { } ;
m_current_block = finalizer ;
// the unwind_context will be pop'ed when entering the finally block
continue ;
2022-11-13 20:56:53 +01:00
}
2021-06-09 06:49:58 +04:30
2022-11-13 20:56:53 +01:00
if ( pc . at_end ( ) )
2021-06-05 15:53:36 +02:00
break ;
2021-06-09 18:19:11 +02:00
2022-11-13 20:56:53 +01:00
if ( will_return )
break ;
2021-06-04 12:07:38 +02:00
}
2023-09-26 16:41:42 +02:00
}
2024-05-01 19:33:49 +02:00
Interpreter : : ResultAndReturnRegister Interpreter : : run_executable ( Executable & executable , BasicBlock const * entry_point )
2023-09-26 16:41:42 +02:00
{
dbgln_if ( JS_BYTECODE_DEBUG , " Bytecode::Interpreter will run unit {:p} " , & executable ) ;
2024-04-05 13:47:41 -07:00
TemporaryChange restore_executable { m_current_executable , GCPtr { executable } } ;
2023-09-26 16:41:42 +02:00
TemporaryChange restore_saved_jump { m_scheduled_jump , static_cast < BasicBlock const * > ( nullptr ) } ;
2024-04-05 13:47:41 -07:00
TemporaryChange restore_realm { m_realm , GCPtr { vm ( ) . current_realm ( ) } } ;
TemporaryChange restore_global_object { m_global_object , GCPtr { m_realm - > global_object ( ) } } ;
TemporaryChange restore_global_declarative_environment { m_global_declarative_environment , GCPtr { m_realm - > global_environment ( ) . declarative_record ( ) } } ;
2023-09-26 16:41:42 +02:00
VERIFY ( ! vm ( ) . execution_context_stack ( ) . is_empty ( ) ) ;
TemporaryChange restore_current_block { m_current_block , entry_point ? : executable . basic_blocks . first ( ) } ;
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm ( ) . running_execution_context ( ) ;
if ( running_execution_context . registers . size ( ) < executable . number_of_registers )
running_execution_context . registers . resize ( executable . number_of_registers ) ;
2023-09-26 16:41:42 +02:00
2024-05-01 19:33:49 +02:00
reg ( Register : : return_value ( ) ) = { } ;
running_execution_context . executable = & executable ;
2023-11-01 00:39:28 +01:00
2024-02-19 13:59:58 +01:00
run_bytecode ( ) ;
2021-06-03 10:46:30 +02:00
2021-06-09 09:11:20 +02:00
dbgln_if ( JS_BYTECODE_DEBUG , " Bytecode::Interpreter did run unit {:p} " , & executable ) ;
2021-06-07 15:17:37 +02:00
if constexpr ( JS_BYTECODE_DEBUG ) {
for ( size_t i = 0 ; i < registers ( ) . size ( ) ; + + i ) {
2023-02-12 21:54:02 -05:00
String value_string ;
2021-06-07 15:17:37 +02:00
if ( registers ( ) [ i ] . is_empty ( ) )
2023-08-07 11:12:38 +02:00
value_string = " (empty) " _string ;
2021-06-07 15:17:37 +02:00
else
2023-08-09 08:49:02 +02:00
value_string = registers ( ) [ i ] . to_string_without_side_effects ( ) ;
2021-06-07 15:17:37 +02:00
dbgln ( " [{:3}] {} " , i , value_string ) ;
}
2021-06-03 10:46:30 +02:00
}
2021-06-05 15:53:36 +02:00
2023-09-26 15:32:46 +02:00
auto return_value = js_undefined ( ) ;
if ( ! reg ( Register : : return_value ( ) ) . is_empty ( ) )
return_value = reg ( Register : : return_value ( ) ) ;
else if ( ! reg ( Register : : saved_return_value ( ) ) . is_empty ( ) )
return_value = reg ( Register : : saved_return_value ( ) ) ;
2023-09-26 11:57:42 +02:00
auto exception = reg ( Register : : exception ( ) ) ;
2023-07-21 17:30:07 +02:00
2021-11-11 00:44:56 +03:30
// At this point we may have already run any queued promise jobs via on_call_stack_emptied,
// in which case this is a no-op.
vm ( ) . run_queued_promise_jobs ( ) ;
2021-06-12 17:32:54 +03:00
vm ( ) . finish_execution_generation ( ) ;
2024-05-01 19:33:49 +02:00
if ( ! exception . is_empty ( ) )
return { throw_completion ( exception ) , vm ( ) . running_execution_context ( ) . registers [ 0 ] } ;
return { return_value , vm ( ) . running_execution_context ( ) . registers [ 0 ] } ;
2021-06-03 10:46:30 +02:00
}
2023-10-20 00:33:51 +02:00
void Interpreter : : enter_unwind_context ( )
2021-06-10 15:04:38 +02:00
{
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm ( ) . running_execution_context ( ) ;
running_execution_context . unwind_contexts . empend (
2023-05-13 18:53:14 +02:00
m_current_executable ,
2023-07-02 15:05:17 +02:00
vm ( ) . running_execution_context ( ) . lexical_environment ) ;
2024-05-01 19:33:49 +02:00
running_execution_context . previously_scheduled_jumps . append ( m_scheduled_jump ) ;
2023-10-21 22:46:40 +02:00
m_scheduled_jump = nullptr ;
2021-06-10 15:04:38 +02:00
}
void Interpreter : : leave_unwind_context ( )
{
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm ( ) . running_execution_context ( ) ;
running_execution_context . unwind_contexts . take_last ( ) ;
2021-06-10 15:04:38 +02:00
}
2024-02-04 08:00:54 +01:00
void Interpreter : : catch_exception ( Operand dst )
2023-11-11 23:19:46 +01:00
{
2024-02-04 08:00:54 +01:00
set ( dst , reg ( Register : : exception ( ) ) ) ;
2023-11-11 23:19:46 +01:00
reg ( Register : : exception ( ) ) = { } ;
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm ( ) . running_execution_context ( ) ;
auto & context = running_execution_context . unwind_contexts . last ( ) ;
2023-11-11 23:19:46 +01:00
VERIFY ( ! context . handler_called ) ;
VERIFY ( context . executable = = & current_executable ( ) ) ;
context . handler_called = true ;
vm ( ) . running_execution_context ( ) . lexical_environment = context . lexical_environment ;
}
2024-04-11 11:07:35 +02:00
void Interpreter : : restore_scheduled_jump ( )
{
2024-05-02 07:42:09 +02:00
m_scheduled_jump = vm ( ) . running_execution_context ( ) . previously_scheduled_jumps . take_last ( ) ;
2024-04-11 11:07:35 +02:00
}
2024-04-11 11:58:18 +02:00
void Interpreter : : leave_finally ( )
{
reg ( Register : : exception ( ) ) = { } ;
2024-05-02 07:42:09 +02:00
m_scheduled_jump = vm ( ) . running_execution_context ( ) . previously_scheduled_jumps . take_last ( ) ;
2024-04-11 11:58:18 +02:00
}
2023-11-12 00:12:21 +01:00
void Interpreter : : enter_object_environment ( Object & object )
{
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm ( ) . running_execution_context ( ) ;
auto & old_environment = running_execution_context . lexical_environment ;
running_execution_context . saved_lexical_environments . append ( old_environment ) ;
running_execution_context . lexical_environment = new_object_environment ( object , true , old_environment ) ;
2023-11-12 00:12:21 +01:00
}
2024-02-04 08:00:54 +01:00
ThrowCompletionOr < NonnullGCPtr < Bytecode : : Executable > > compile ( VM & vm , ASTNode const & node , ReadonlySpan < FunctionParameter > parameters , FunctionKind kind , DeprecatedFlyString const & name )
2023-06-22 15:59:18 +02:00
{
2024-02-04 08:00:54 +01:00
auto executable_result = Bytecode : : Generator : : generate ( vm , node , parameters , kind ) ;
2023-06-22 15:59:18 +02:00
if ( executable_result . is_error ( ) )
return vm . throw_completion < InternalError > ( ErrorType : : NotImplemented , TRY_OR_THROW_OOM ( vm , executable_result . error ( ) . to_string ( ) ) ) ;
auto bytecode_executable = executable_result . release_value ( ) ;
bytecode_executable - > name = name ;
2023-06-26 20:10:11 +02:00
2023-06-22 15:59:18 +02:00
if ( Bytecode : : g_dump_bytecode )
bytecode_executable - > dump ( ) ;
return bytecode_executable ;
}
2021-06-03 10:46:30 +02:00
}
2023-09-27 10:10:00 +02:00
namespace JS : : Bytecode {
2023-12-16 17:49:34 +03:30
ByteString Instruction : : to_byte_string ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
# define __BYTECODE_OP(op) \
case Instruction : : Type : : op : \
2023-12-16 17:49:34 +03:30
return static_cast < Bytecode : : Op : : op const & > ( * this ) . to_byte_string_impl ( executable ) ;
2023-09-27 10:10:00 +02:00
switch ( type ( ) ) {
ENUMERATE_BYTECODE_OPS ( __BYTECODE_OP )
default :
VERIFY_NOT_REACHED ( ) ;
}
# undef __BYTECODE_OP
}
}
namespace JS : : Bytecode : : Op {
2024-02-04 08:00:54 +01:00
static void dump_object ( Object & o , HashTable < Object const * > & seen , int indent = 0 )
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
if ( seen . contains ( & o ) )
return ;
seen . set ( & o ) ;
for ( auto & it : o . shape ( ) . property_table ( ) ) {
auto value = o . get_direct ( it . value . offset ) ;
dbgln ( " {} {} -> {} " , String : : repeated ( ' ' , indent ) . release_value ( ) , it . key . to_display_string ( ) , value ) ;
if ( value . is_object ( ) ) {
dump_object ( value . as_object ( ) , seen , indent + 2 ) ;
}
}
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ThrowCompletionOr < void > Dump : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
auto value = interpreter . get ( m_value ) ;
dbgln ( " (DUMP) {}: {} " , m_text , value ) ;
if ( value . is_object ( ) ) {
HashTable < Object const * > seen ;
dump_object ( value . as_object ( ) , seen ) ;
}
return { } ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ThrowCompletionOr < void > End : : execute_impl ( Bytecode : : Interpreter & ) const
2023-09-27 10:10:00 +02:00
{
2023-09-27 11:31:23 +02:00
// Handled in the interpreter loop.
__builtin_unreachable ( ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-20 11:59:46 +01:00
# define JS_DEFINE_EXECUTE_FOR_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
2023-09-27 10:10:00 +02:00
ThrowCompletionOr < void > OpTitleCase : : execute_impl ( Bytecode : : Interpreter & interpreter ) const \
{ \
auto & vm = interpreter . vm ( ) ; \
2024-02-04 08:00:54 +01:00
auto lhs = interpreter . get ( m_lhs ) ; \
auto rhs = interpreter . get ( m_rhs ) ; \
interpreter . set ( m_dst , TRY ( op_snake_case ( vm , lhs , rhs ) ) ) ; \
2023-09-27 10:10:00 +02:00
return { } ; \
}
2024-02-20 11:59:46 +01:00
# define JS_DEFINE_TO_BYTE_STRING_FOR_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
ByteString OpTitleCase : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const \
{ \
return ByteString : : formatted ( # OpTitleCase " {}, {}, {} " , \
format_operand ( " dst " sv , m_dst , executable ) , \
format_operand ( " lhs " sv , m_lhs , executable ) , \
format_operand ( " rhs " sv , m_rhs , executable ) ) ; \
}
JS_ENUMERATE_COMMON_BINARY_OPS_WITHOUT_FAST_PATH ( JS_DEFINE_EXECUTE_FOR_COMMON_BINARY_OP )
JS_ENUMERATE_COMMON_BINARY_OPS_WITHOUT_FAST_PATH ( JS_DEFINE_TO_BYTE_STRING_FOR_COMMON_BINARY_OP )
JS_ENUMERATE_COMMON_BINARY_OPS_WITH_FAST_PATH ( JS_DEFINE_TO_BYTE_STRING_FOR_COMMON_BINARY_OP )
ThrowCompletionOr < void > Add : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_number ( ) & & rhs . is_number ( ) ) {
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
if ( ! Checked < i32 > : : addition_would_overflow ( lhs . as_i32 ( ) , rhs . as_i32 ( ) ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) + rhs . as_i32 ( ) ) ) ;
return { } ;
}
}
interpreter . set ( m_dst , Value ( lhs . as_double ( ) + rhs . as_double ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( add ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > Mul : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_number ( ) & & rhs . is_number ( ) ) {
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
if ( ! Checked < i32 > : : multiplication_would_overflow ( lhs . as_i32 ( ) , rhs . as_i32 ( ) ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) * rhs . as_i32 ( ) ) ) ;
return { } ;
}
}
interpreter . set ( m_dst , Value ( lhs . as_double ( ) * rhs . as_double ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( mul ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > Sub : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_number ( ) & & rhs . is_number ( ) ) {
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
if ( ! Checked < i32 > : : addition_would_overflow ( lhs . as_i32 ( ) , - rhs . as_i32 ( ) ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) - rhs . as_i32 ( ) ) ) ;
return { } ;
}
}
interpreter . set ( m_dst , Value ( lhs . as_double ( ) - rhs . as_double ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( sub ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > BitwiseXor : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) ^ rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( bitwise_xor ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > BitwiseAnd : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) & rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( bitwise_and ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > BitwiseOr : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) | rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( bitwise_or ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > UnsignedRightShift : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
2024-03-04 10:56:21 +01:00
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
2024-02-20 11:59:46 +01:00
auto const shift_count = static_cast < u32 > ( rhs . as_i32 ( ) ) % 32 ;
interpreter . set ( m_dst , Value ( static_cast < u32 > ( lhs . as_i32 ( ) ) > > shift_count ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( unsigned_right_shift ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > RightShift : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
2024-03-04 10:56:21 +01:00
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
2024-02-20 11:59:46 +01:00
auto const shift_count = static_cast < u32 > ( rhs . as_i32 ( ) ) % 32 ;
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) > > shift_count ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( right_shift ( vm , lhs , rhs ) ) ) ;
return { } ;
}
2024-03-04 10:01:40 +01:00
ThrowCompletionOr < void > LeftShift : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
2024-03-04 10:56:21 +01:00
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
2024-03-04 10:01:40 +01:00
auto const shift_count = static_cast < u32 > ( rhs . as_i32 ( ) ) % 32 ;
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) < < shift_count ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( left_shift ( vm , lhs , rhs ) ) ) ;
return { } ;
}
2024-02-20 11:59:46 +01:00
ThrowCompletionOr < void > LessThan : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) < rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( less_than ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > LessThanEquals : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) < = rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( less_than_equals ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > GreaterThan : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) > rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( greater_than ( vm , lhs , rhs ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > GreaterThanEquals : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const lhs = interpreter . get ( m_lhs ) ;
auto const rhs = interpreter . get ( m_rhs ) ;
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) > = rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , TRY ( greater_than_equals ( vm , lhs , rhs ) ) ) ;
return { } ;
}
2023-09-27 10:10:00 +02:00
static ThrowCompletionOr < Value > not_ ( VM & , Value value )
{
return Value ( ! value . to_boolean ( ) ) ;
}
static ThrowCompletionOr < Value > typeof_ ( VM & vm , Value value )
{
return PrimitiveString : : create ( vm , value . typeof ( ) ) ;
}
# define JS_DEFINE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \
ThrowCompletionOr < void > OpTitleCase : : execute_impl ( Bytecode : : Interpreter & interpreter ) const \
{ \
auto & vm = interpreter . vm ( ) ; \
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( op_snake_case ( vm , interpreter . get ( src ( ) ) ) ) ) ; \
2023-09-27 10:10:00 +02:00
return { } ; \
} \
2024-02-04 08:00:54 +01:00
ByteString OpTitleCase : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const \
2023-09-27 10:10:00 +02:00
{ \
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( # OpTitleCase " {}, {} " , \
format_operand ( " dst " sv , dst ( ) , executable ) , \
format_operand ( " src " sv , src ( ) , executable ) ) ; \
2023-09-27 10:10:00 +02:00
}
JS_ENUMERATE_COMMON_UNARY_OPS ( JS_DEFINE_COMMON_UNARY_OP )
ThrowCompletionOr < void > NewArray : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto array = MUST ( Array : : create ( interpreter . realm ( ) , 0 ) ) ;
for ( size_t i = 0 ; i < m_element_count ; i + + ) {
auto & value = interpreter . reg ( Register ( m_elements [ 0 ] . index ( ) + i ) ) ;
array - > indexed_properties ( ) . put ( i , value , default_attributes ) ;
}
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , array ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
2023-11-17 22:07:23 +02:00
ThrowCompletionOr < void > NewPrimitiveArray : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto array = MUST ( Array : : create ( interpreter . realm ( ) , 0 ) ) ;
2024-03-03 12:37:28 +01:00
for ( size_t i = 0 ; i < m_element_count ; i + + )
array - > indexed_properties ( ) . put ( i , m_elements [ i ] , default_attributes ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , array ) ;
2023-11-17 22:07:23 +02:00
return { } ;
}
2024-02-04 08:00:54 +01:00
ThrowCompletionOr < void > ArrayAppend : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return append ( interpreter . vm ( ) , interpreter . get ( dst ( ) ) , interpreter . get ( src ( ) ) , m_is_spread ) ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > ImportCall : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto specifier = interpreter . get ( m_specifier ) ;
auto options_value = interpreter . get ( m_options ) ;
interpreter . set ( dst ( ) , TRY ( perform_import_call ( vm , specifier , options_value ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > IteratorToArray : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( iterator_to_array ( interpreter . vm ( ) , interpreter . get ( iterator ( ) ) ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > NewObject : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto & realm = * vm . current_realm ( ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , Object : : create ( realm , realm . intrinsics ( ) . object_prototype ( ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > NewRegExp : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) ,
new_regexp (
interpreter . vm ( ) ,
interpreter . current_executable ( ) . regex_table - > get ( m_regex_index ) ,
interpreter . current_executable ( ) . get_string ( m_source_index ) ,
interpreter . current_executable ( ) . get_string ( m_flags_index ) ) ) ;
return { } ;
}
# define JS_DEFINE_NEW_BUILTIN_ERROR_OP(ErrorName) \
ThrowCompletionOr < void > New # # ErrorName : : execute_impl ( Bytecode : : Interpreter & interpreter ) const \
{ \
auto & vm = interpreter . vm ( ) ; \
auto & realm = * vm . current_realm ( ) ; \
interpreter . set ( dst ( ) , ErrorName : : create ( realm , interpreter . current_executable ( ) . get_string ( m_error_string ) ) ) ; \
return { } ; \
} \
ByteString New # # ErrorName : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const \
{ \
return ByteString : : formatted ( " New " # ErrorName " {}, {} " , \
format_operand ( " dst " sv , m_dst , executable ) , \
executable . string_table - > get ( m_error_string ) ) ; \
2023-09-27 10:10:00 +02:00
}
JS_ENUMERATE_NEW_BUILTIN_ERROR_OPS ( JS_DEFINE_NEW_BUILTIN_ERROR_OP )
ThrowCompletionOr < void > CopyObjectExcludingProperties : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto & realm = * vm . current_realm ( ) ;
2024-02-04 08:00:54 +01:00
auto from_object = interpreter . get ( m_from_object ) ;
2023-09-27 10:10:00 +02:00
auto to_object = Object : : create ( realm , realm . intrinsics ( ) . object_prototype ( ) ) ;
HashTable < PropertyKey > excluded_names ;
for ( size_t i = 0 ; i < m_excluded_names_count ; + + i ) {
2024-02-04 08:00:54 +01:00
excluded_names . set ( TRY ( interpreter . get ( m_excluded_names [ i ] ) . to_property_key ( vm ) ) ) ;
2023-09-27 10:10:00 +02:00
}
TRY ( to_object - > copy_data_properties ( vm , from_object , excluded_names ) ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , to_object ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > ConcatString : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto string = TRY ( interpreter . get ( src ( ) ) . to_primitive_string ( vm ) ) ;
interpreter . set ( dst ( ) , PrimitiveString : : create ( vm , interpreter . get ( dst ( ) ) . as_string ( ) , string ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > GetVariable : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( get_variable ( interpreter , interpreter . current_executable ( ) . get_identifier ( m_identifier ) , interpreter . current_executable ( ) . environment_variable_caches [ m_cache_index ] ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > GetCalleeAndThisFromEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2023-11-10 13:00:36 +01:00
auto callee_and_this = TRY ( get_callee_and_this_from_environment (
interpreter ,
interpreter . current_executable ( ) . get_identifier ( m_identifier ) ,
interpreter . current_executable ( ) . environment_variable_caches [ m_cache_index ] ) ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( m_callee , callee_and_this . callee ) ;
interpreter . set ( m_this_value , callee_and_this . this_value ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > GetGlobal : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( get_global ( interpreter , interpreter . current_executable ( ) . get_identifier ( m_identifier ) , interpreter . current_executable ( ) . global_variable_caches [ m_cache_index ] ) ) ) ;
2023-10-20 12:56:12 +02:00
return { } ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > DeleteVariable : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const & string = interpreter . current_executable ( ) . get_identifier ( m_identifier ) ;
auto reference = TRY ( vm . resolve_binding ( string ) ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , Value ( TRY ( reference . delete_ ( vm ) ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > CreateLexicalEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto make_and_swap_envs = [ & ] ( auto & old_environment ) {
GCPtr < Environment > environment = new_declarative_environment ( * old_environment ) . ptr ( ) ;
swap ( old_environment , environment ) ;
return environment ;
} ;
2024-05-01 19:33:49 +02:00
auto & running_execution_context = interpreter . vm ( ) . running_execution_context ( ) ;
running_execution_context . saved_lexical_environments . append ( make_and_swap_envs ( running_execution_context . lexical_environment ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > EnterObjectEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto object = TRY ( interpreter . get ( m_object ) . to_object ( interpreter . vm ( ) ) ) ;
2023-11-12 00:12:21 +01:00
interpreter . enter_object_environment ( * object ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
2023-11-11 23:19:46 +01:00
ThrowCompletionOr < void > Catch : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
interpreter . catch_exception ( dst ( ) ) ;
2023-11-11 23:19:46 +01:00
return { } ;
}
2024-04-11 11:58:18 +02:00
ThrowCompletionOr < void > LeaveFinally : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
interpreter . leave_finally ( ) ;
return { } ;
}
2024-04-11 11:07:35 +02:00
ThrowCompletionOr < void > RestoreScheduledJump : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
interpreter . restore_scheduled_jump ( ) ;
return { } ;
}
2023-09-27 10:10:00 +02:00
ThrowCompletionOr < void > CreateVariable : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto const & name = interpreter . current_executable ( ) . get_identifier ( m_identifier ) ;
2023-10-29 00:21:43 +02:00
return create_variable ( interpreter . vm ( ) , name , m_mode , m_is_global , m_is_immutable , m_is_strict ) ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > SetVariable : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const & name = interpreter . current_executable ( ) . get_identifier ( m_identifier ) ;
2023-11-16 07:13:35 +01:00
TRY ( set_variable ( vm ,
name ,
2024-02-04 08:00:54 +01:00
interpreter . get ( src ( ) ) ,
2023-11-16 07:13:35 +01:00
m_mode ,
m_initialization_mode ,
interpreter . current_executable ( ) . environment_variable_caches [ m_cache_index ] ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
2023-09-27 11:31:23 +02:00
ThrowCompletionOr < void > SetLocal : : execute_impl ( Bytecode : : Interpreter & ) const
2023-09-27 10:10:00 +02:00
{
2023-09-27 11:31:23 +02:00
// Handled in the interpreter loop.
__builtin_unreachable ( ) ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > GetById : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-03-29 11:26:10 -04:00
auto base_identifier = interpreter . current_executable ( ) . get_identifier ( m_base_identifier ) ;
auto const & property_identifier = interpreter . current_executable ( ) . get_identifier ( m_property ) ;
2024-02-04 08:00:54 +01:00
auto base_value = interpreter . get ( base ( ) ) ;
2023-11-05 14:33:54 +01:00
auto & cache = interpreter . current_executable ( ) . property_lookup_caches [ m_cache_index ] ;
2024-03-29 11:26:10 -04:00
interpreter . set ( dst ( ) , TRY ( get_by_id ( interpreter . vm ( ) , base_identifier , property_identifier , base_value , base_value , cache ) ) ) ;
2023-10-18 13:26:47 +02:00
return { } ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > GetByIdWithThis : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto base_value = interpreter . get ( m_base ) ;
auto this_value = interpreter . get ( m_this_value ) ;
2023-11-05 14:33:54 +01:00
auto & cache = interpreter . current_executable ( ) . property_lookup_caches [ m_cache_index ] ;
2024-03-29 11:26:10 -04:00
interpreter . set ( dst ( ) , TRY ( get_by_id ( interpreter . vm ( ) , { } , interpreter . current_executable ( ) . get_identifier ( m_property ) , base_value , this_value , cache ) ) ) ;
2023-10-18 13:26:47 +02:00
return { } ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > GetPrivateById : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const & name = interpreter . current_executable ( ) . get_identifier ( m_property ) ;
2024-02-04 08:00:54 +01:00
auto base_value = interpreter . get ( m_base ) ;
2023-09-27 10:10:00 +02:00
auto private_reference = make_private_reference ( vm , base_value , name ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( private_reference . get_value ( vm ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > HasPrivateId : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto base = interpreter . get ( m_base ) ;
if ( ! base . is_object ( ) )
2023-09-27 10:10:00 +02:00
return vm . throw_completion < TypeError > ( ErrorType : : InOperatorWithObject ) ;
auto private_environment = vm . running_execution_context ( ) . private_environment ;
VERIFY ( private_environment ) ;
auto private_name = private_environment - > resolve_private_identifier ( interpreter . current_executable ( ) . get_identifier ( m_property ) ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , Value ( base . as_object ( ) . private_element_find ( private_name ) ! = nullptr ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > PutById : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto value = interpreter . get ( m_src ) ;
auto base = interpreter . get ( m_base ) ;
2024-03-29 12:10:52 -04:00
auto base_identifier = interpreter . current_executable ( ) . get_identifier ( m_base_identifier ) ;
2023-09-27 10:10:00 +02:00
PropertyKey name = interpreter . current_executable ( ) . get_identifier ( m_property ) ;
2023-11-08 20:51:26 +01:00
auto & cache = interpreter . current_executable ( ) . property_lookup_caches [ m_cache_index ] ;
2024-03-29 12:10:52 -04:00
TRY ( put_by_property_key ( vm , base , base , value , base_identifier , name , m_kind , & cache ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > PutByIdWithThis : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto value = interpreter . get ( m_src ) ;
auto base = interpreter . get ( m_base ) ;
2023-09-27 10:10:00 +02:00
PropertyKey name = interpreter . current_executable ( ) . get_identifier ( m_property ) ;
2023-11-08 20:51:26 +01:00
auto & cache = interpreter . current_executable ( ) . property_lookup_caches [ m_cache_index ] ;
2024-03-29 12:10:52 -04:00
TRY ( put_by_property_key ( vm , base , interpreter . get ( m_this_value ) , value , { } , name , m_kind , & cache ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > PutPrivateById : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto value = interpreter . get ( m_src ) ;
auto object = TRY ( interpreter . get ( m_base ) . to_object ( vm ) ) ;
2023-09-27 10:10:00 +02:00
auto name = interpreter . current_executable ( ) . get_identifier ( m_property ) ;
auto private_reference = make_private_reference ( vm , object , name ) ;
TRY ( private_reference . put_value ( vm , value ) ) ;
return { } ;
}
ThrowCompletionOr < void > DeleteById : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto base_value = interpreter . get ( m_base ) ;
interpreter . set ( dst ( ) , TRY ( Bytecode : : delete_by_id ( interpreter , base_value , m_property ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > DeleteByIdWithThis : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto base_value = interpreter . get ( m_base ) ;
2023-09-27 10:10:00 +02:00
auto const & identifier = interpreter . current_executable ( ) . get_identifier ( m_property ) ;
bool strict = vm . in_strict_mode ( ) ;
2024-02-04 08:00:54 +01:00
auto reference = Reference { base_value , identifier , interpreter . get ( m_this_value ) , strict } ;
interpreter . set ( dst ( ) , Value ( TRY ( reference . delete_ ( vm ) ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > Jump : : execute_impl ( Bytecode : : Interpreter & ) const
{
// Handled in the interpreter loop.
2023-09-27 11:31:23 +02:00
__builtin_unreachable ( ) ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > ResolveThisBinding : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & cached_this_value = interpreter . reg ( Register : : this_value ( ) ) ;
if ( cached_this_value . is_empty ( ) ) {
// OPTIMIZATION: Because the value of 'this' cannot be reassigned during a function execution, it's
// resolved once and then saved for subsequent use.
auto & vm = interpreter . vm ( ) ;
cached_this_value = TRY ( vm . resolve_this_binding ( ) ) ;
}
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , cached_this_value ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
// https://tc39.es/ecma262/#sec-makesuperpropertyreference
ThrowCompletionOr < void > ResolveSuperBase : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
// 1. Let env be GetThisEnvironment().
auto & env = verify_cast < FunctionEnvironment > ( * get_this_environment ( vm ) ) ;
// 2. Assert: env.HasSuperBinding() is true.
VERIFY ( env . has_super_binding ( ) ) ;
// 3. Let baseValue be ? env.GetSuperBase().
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( env . get_super_base ( ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > GetNewTarget : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , interpreter . vm ( ) . get_new_target ( ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > GetImportMeta : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , interpreter . vm ( ) . get_import_meta ( ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
2024-02-04 08:00:54 +01:00
ThrowCompletionOr < void > JumpIf : : execute_impl ( Bytecode : : Interpreter & ) const
{
// Handled in the interpreter loop.
__builtin_unreachable ( ) ;
}
ThrowCompletionOr < void > JumpUndefined : : execute_impl ( Bytecode : : Interpreter & ) const
2023-09-27 10:10:00 +02:00
{
// Handled in the interpreter loop.
2023-09-27 11:31:23 +02:00
__builtin_unreachable ( ) ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > JumpNullish : : execute_impl ( Bytecode : : Interpreter & ) const
{
// Handled in the interpreter loop.
2023-09-27 11:31:23 +02:00
__builtin_unreachable ( ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ThrowCompletionOr < void > Mov : : execute_impl ( Bytecode : : Interpreter & ) const
2023-09-27 10:10:00 +02:00
{
// Handled in the interpreter loop.
2023-09-27 11:31:23 +02:00
__builtin_unreachable ( ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-20 15:59:45 +01:00
static ThrowCompletionOr < Value > dispatch_builtin_call ( Bytecode : : Interpreter & interpreter , Bytecode : : Builtin builtin , ReadonlySpan < Operand > arguments )
2023-11-30 19:49:29 +01:00
{
switch ( builtin ) {
case Builtin : : MathAbs :
2024-02-20 15:59:45 +01:00
return TRY ( MathObject : : abs_impl ( interpreter . vm ( ) , interpreter . get ( arguments [ 0 ] ) ) ) ;
2023-11-30 19:49:29 +01:00
case Builtin : : MathLog :
2024-02-20 15:59:45 +01:00
return TRY ( MathObject : : log_impl ( interpreter . vm ( ) , interpreter . get ( arguments [ 0 ] ) ) ) ;
case Builtin : : MathPow :
return TRY ( MathObject : : pow_impl ( interpreter . vm ( ) , interpreter . get ( arguments [ 0 ] ) , interpreter . get ( arguments [ 1 ] ) ) ) ;
2023-11-30 19:49:29 +01:00
case Builtin : : MathExp :
2024-02-20 15:59:45 +01:00
return TRY ( MathObject : : exp_impl ( interpreter . vm ( ) , interpreter . get ( arguments [ 0 ] ) ) ) ;
2023-11-30 19:49:29 +01:00
case Builtin : : MathCeil :
2024-02-20 15:59:45 +01:00
return TRY ( MathObject : : ceil_impl ( interpreter . vm ( ) , interpreter . get ( arguments [ 0 ] ) ) ) ;
2023-11-30 19:49:29 +01:00
case Builtin : : MathFloor :
2024-02-20 15:59:45 +01:00
return TRY ( MathObject : : floor_impl ( interpreter . vm ( ) , interpreter . get ( arguments [ 0 ] ) ) ) ;
2023-11-30 19:49:29 +01:00
case Builtin : : MathRound :
2024-02-20 15:59:45 +01:00
return TRY ( MathObject : : round_impl ( interpreter . vm ( ) , interpreter . get ( arguments [ 0 ] ) ) ) ;
2023-11-30 19:49:29 +01:00
case Builtin : : MathSqrt :
2024-02-20 15:59:45 +01:00
return TRY ( MathObject : : sqrt_impl ( interpreter . vm ( ) , interpreter . get ( arguments [ 0 ] ) ) ) ;
2023-11-30 19:49:29 +01:00
case Bytecode : : Builtin : : __Count :
VERIFY_NOT_REACHED ( ) ;
}
VERIFY_NOT_REACHED ( ) ;
}
2023-09-27 10:10:00 +02:00
ThrowCompletionOr < void > Call : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto callee = interpreter . get ( m_callee ) ;
2023-09-27 10:10:00 +02:00
2023-10-26 15:13:08 +02:00
TRY ( throw_if_needed_for_call ( interpreter , callee , call_type ( ) , expression_string ( ) ) ) ;
2023-09-27 10:10:00 +02:00
2024-02-20 21:29:58 +01:00
if ( m_builtin . has_value ( )
& & m_argument_count = = Bytecode : : builtin_argument_count ( m_builtin . value ( ) )
& & callee . is_object ( )
& & interpreter . realm ( ) . get_builtin_value ( m_builtin . value ( ) ) = = & callee . as_object ( ) ) {
2024-02-20 15:59:45 +01:00
interpreter . set ( dst ( ) , TRY ( dispatch_builtin_call ( interpreter , m_builtin . value ( ) , { m_arguments , m_argument_count } ) ) ) ;
2023-11-30 19:49:29 +01:00
return { } ;
}
2024-02-20 15:59:45 +01:00
Vector < Value > argument_values ;
argument_values . ensure_capacity ( m_argument_count ) ;
for ( size_t i = 0 ; i < m_argument_count ; + + i )
argument_values . unchecked_append ( interpreter . get ( m_arguments [ i ] ) ) ;
interpreter . set ( dst ( ) , TRY ( perform_call ( interpreter , interpreter . get ( m_this_value ) , call_type ( ) , callee , argument_values ) ) ) ;
2023-10-20 13:20:28 +02:00
return { } ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > CallWithArgumentArray : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto callee = interpreter . get ( m_callee ) ;
2023-10-26 15:13:08 +02:00
TRY ( throw_if_needed_for_call ( interpreter , callee , call_type ( ) , expression_string ( ) ) ) ;
2024-02-04 08:00:54 +01:00
auto argument_values = argument_list_evaluation ( interpreter . vm ( ) , interpreter . get ( arguments ( ) ) ) ;
interpreter . set ( dst ( ) , TRY ( perform_call ( interpreter , interpreter . get ( m_this_value ) , call_type ( ) , callee , move ( argument_values ) ) ) ) ;
2023-10-20 13:20:28 +02:00
return { } ;
2023-09-27 10:10:00 +02:00
}
// 13.3.7.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
ThrowCompletionOr < void > SuperCallWithArgumentArray : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( super_call_with_argument_array ( interpreter . vm ( ) , interpreter . get ( arguments ( ) ) , m_is_synthetic ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > NewFunction : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , new_function ( vm , m_function_node , m_lhs_name , m_home_object ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > Return : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
if ( m_value . has_value ( ) )
interpreter . do_return ( interpreter . get ( * m_value ) ) ;
else
interpreter . do_return ( js_undefined ( ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > Increment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto old_value = interpreter . get ( dst ( ) ) ;
2024-01-27 20:51:11 +01:00
// OPTIMIZATION: Fast path for Int32 values.
if ( old_value . is_int32 ( ) ) {
auto integer_value = old_value . as_i32 ( ) ;
if ( integer_value ! = NumericLimits < i32 > : : max ( ) ) [[likely]] {
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , Value { integer_value + 1 } ) ;
2024-01-27 20:51:11 +01:00
return { } ;
}
}
old_value = TRY ( old_value . to_numeric ( vm ) ) ;
2023-09-27 10:10:00 +02:00
if ( old_value . is_number ( ) )
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , Value ( old_value . as_double ( ) + 1 ) ) ;
2023-09-27 10:10:00 +02:00
else
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , BigInt : : create ( vm , old_value . as_bigint ( ) . big_integer ( ) . plus ( Crypto : : SignedBigInteger { 1 } ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
2024-02-20 11:45:01 +01:00
ThrowCompletionOr < void > PostfixIncrement : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto old_value = interpreter . get ( m_src ) ;
// OPTIMIZATION: Fast path for Int32 values.
if ( old_value . is_int32 ( ) ) {
auto integer_value = old_value . as_i32 ( ) ;
if ( integer_value ! = NumericLimits < i32 > : : max ( ) ) [[likely]] {
interpreter . set ( m_dst , old_value ) ;
interpreter . set ( m_src , Value { integer_value + 1 } ) ;
return { } ;
}
}
old_value = TRY ( old_value . to_numeric ( vm ) ) ;
interpreter . set ( m_dst , old_value ) ;
if ( old_value . is_number ( ) )
interpreter . set ( m_src , Value ( old_value . as_double ( ) + 1 ) ) ;
else
interpreter . set ( m_src , BigInt : : create ( vm , old_value . as_bigint ( ) . big_integer ( ) . plus ( Crypto : : SignedBigInteger { 1 } ) ) ) ;
return { } ;
}
2023-09-27 10:10:00 +02:00
ThrowCompletionOr < void > Decrement : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto old_value = interpreter . get ( dst ( ) ) ;
old_value = TRY ( old_value . to_numeric ( vm ) ) ;
2023-09-27 10:10:00 +02:00
if ( old_value . is_number ( ) )
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , Value ( old_value . as_double ( ) - 1 ) ) ;
2023-09-27 10:10:00 +02:00
else
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , BigInt : : create ( vm , old_value . as_bigint ( ) . big_integer ( ) . minus ( Crypto : : SignedBigInteger { 1 } ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
2024-02-20 11:45:01 +01:00
ThrowCompletionOr < void > PostfixDecrement : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto old_value = interpreter . get ( m_src ) ;
old_value = TRY ( old_value . to_numeric ( vm ) ) ;
interpreter . set ( m_dst , old_value ) ;
if ( old_value . is_number ( ) )
interpreter . set ( m_src , Value ( old_value . as_double ( ) - 1 ) ) ;
else
interpreter . set ( m_src , BigInt : : create ( vm , old_value . as_bigint ( ) . big_integer ( ) . minus ( Crypto : : SignedBigInteger { 1 } ) ) ) ;
return { } ;
}
2023-09-27 10:10:00 +02:00
ThrowCompletionOr < void > Throw : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
return throw_completion ( interpreter . get ( src ( ) ) ) ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > ThrowIfNotObject : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto src = interpreter . get ( m_src ) ;
if ( ! src . is_object ( ) )
return vm . throw_completion < TypeError > ( ErrorType : : NotAnObject , src . to_string_without_side_effects ( ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > ThrowIfNullish : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto value = interpreter . get ( m_src ) ;
2023-09-27 10:10:00 +02:00
if ( value . is_nullish ( ) )
return vm . throw_completion < TypeError > ( ErrorType : : NotObjectCoercible , value . to_string_without_side_effects ( ) ) ;
return { } ;
}
2024-02-04 08:00:54 +01:00
ThrowCompletionOr < void > ThrowIfTDZ : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto value = interpreter . get ( m_src ) ;
if ( value . is_empty ( ) )
return vm . throw_completion < ReferenceError > ( ErrorType : : BindingNotInitialized , value . to_string_without_side_effects ( ) ) ;
return { } ;
}
2023-09-27 10:10:00 +02:00
ThrowCompletionOr < void > EnterUnwindContext : : execute_impl ( Bytecode : : Interpreter & ) const
{
// Handled in the interpreter loop.
2023-09-27 11:31:23 +02:00
__builtin_unreachable ( ) ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > ScheduleJump : : execute_impl ( Bytecode : : Interpreter & ) const
{
// Handled in the interpreter loop.
2023-09-27 11:31:23 +02:00
__builtin_unreachable ( ) ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > LeaveLexicalEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-05-01 19:33:49 +02:00
auto & running_execution_context = interpreter . vm ( ) . running_execution_context ( ) ;
running_execution_context . lexical_environment = running_execution_context . saved_lexical_environments . take_last ( ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > LeaveUnwindContext : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
interpreter . leave_unwind_context ( ) ;
return { } ;
}
ThrowCompletionOr < void > ContinuePendingUnwind : : execute_impl ( Bytecode : : Interpreter & ) const
{
// Handled in the interpreter loop.
2023-09-27 11:31:23 +02:00
__builtin_unreachable ( ) ;
2023-09-27 10:10:00 +02:00
}
ThrowCompletionOr < void > Yield : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto yielded_value = interpreter . get ( m_value ) . value_or ( js_undefined ( ) ) ;
2023-09-27 10:10:00 +02:00
auto object = Object : : create ( interpreter . realm ( ) , nullptr ) ;
object - > define_direct_property ( " result " , yielded_value , JS : : default_attributes ) ;
if ( m_continuation_label . has_value ( ) )
// FIXME: If we get a pointer, which is not accurately representable as a double
// will cause this to explode
object - > define_direct_property ( " continuation " , Value ( static_cast < double > ( reinterpret_cast < u64 > ( & m_continuation_label - > block ( ) ) ) ) , JS : : default_attributes ) ;
else
object - > define_direct_property ( " continuation " , Value ( 0 ) , JS : : default_attributes ) ;
object - > define_direct_property ( " isAwait " , Value ( false ) , JS : : default_attributes ) ;
interpreter . do_return ( object ) ;
2024-02-04 08:00:54 +01:00
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > Await : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto yielded_value = interpreter . get ( m_argument ) . value_or ( js_undefined ( ) ) ;
2023-09-27 10:10:00 +02:00
auto object = Object : : create ( interpreter . realm ( ) , nullptr ) ;
object - > define_direct_property ( " result " , yielded_value , JS : : default_attributes ) ;
// FIXME: If we get a pointer, which is not accurately representable as a double
// will cause this to explode
object - > define_direct_property ( " continuation " , Value ( static_cast < double > ( reinterpret_cast < u64 > ( & m_continuation_label . block ( ) ) ) ) , JS : : default_attributes ) ;
object - > define_direct_property ( " isAwait " , Value ( true ) , JS : : default_attributes ) ;
interpreter . do_return ( object ) ;
return { } ;
}
ThrowCompletionOr < void > GetByValue : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-03-29 11:26:10 -04:00
auto base_identifier = interpreter . current_executable ( ) . get_identifier ( m_base_identifier ) ;
interpreter . set ( dst ( ) , TRY ( get_by_value ( interpreter . vm ( ) , base_identifier , interpreter . get ( m_base ) , interpreter . get ( m_property ) ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > GetByValueWithThis : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto property_key_value = interpreter . get ( m_property ) ;
auto object = TRY ( interpreter . get ( m_base ) . to_object ( vm ) ) ;
2023-09-27 10:10:00 +02:00
auto property_key = TRY ( property_key_value . to_property_key ( vm ) ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( object - > internal_get ( property_key , interpreter . get ( m_this_value ) ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > PutByValue : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto value = interpreter . get ( m_src ) ;
2024-03-29 12:10:52 -04:00
auto base_identifier = interpreter . current_executable ( ) . get_identifier ( m_base_identifier ) ;
TRY ( put_by_value ( vm , interpreter . get ( m_base ) , base_identifier , interpreter . get ( m_property ) , value , m_kind ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > PutByValueWithThis : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto value = interpreter . get ( m_src ) ;
auto base = interpreter . get ( m_base ) ;
auto property_key = m_kind ! = PropertyKind : : Spread ? TRY ( interpreter . get ( m_property ) . to_property_key ( vm ) ) : PropertyKey { } ;
2024-03-29 12:10:52 -04:00
TRY ( put_by_property_key ( vm , base , interpreter . get ( m_this_value ) , value , { } , property_key , m_kind ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > DeleteByValue : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto base_value = interpreter . get ( m_base ) ;
auto property_key_value = interpreter . get ( m_property ) ;
interpreter . set ( dst ( ) , TRY ( delete_by_value ( interpreter , base_value , property_key_value ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > DeleteByValueWithThis : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto property_key_value = interpreter . get ( m_property ) ;
auto base_value = interpreter . get ( m_base ) ;
auto this_value = interpreter . get ( m_this_value ) ;
interpreter . set ( dst ( ) , TRY ( delete_by_value_with_this ( interpreter , base_value , property_key_value , this_value ) ) ) ;
2023-10-29 21:37:52 +01:00
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > GetIterator : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( get_iterator ( vm , interpreter . get ( iterable ( ) ) , m_hint ) ) ) ;
2023-12-07 10:44:41 +01:00
return { } ;
}
ThrowCompletionOr < void > GetObjectFromIteratorRecord : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto & iterator_record = verify_cast < IteratorRecord > ( interpreter . get ( m_iterator_record ) . as_object ( ) ) ;
interpreter . set ( m_object , iterator_record . iterator ) ;
2023-12-07 10:44:41 +01:00
return { } ;
}
ThrowCompletionOr < void > GetNextMethodFromIteratorRecord : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
auto & iterator_record = verify_cast < IteratorRecord > ( interpreter . get ( m_iterator_record ) . as_object ( ) ) ;
interpreter . set ( m_next_method , iterator_record . next_method ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > GetMethod : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto identifier = interpreter . current_executable ( ) . get_identifier ( m_property ) ;
2024-02-04 08:00:54 +01:00
auto method = TRY ( interpreter . get ( m_object ) . get_method ( vm , identifier ) ) ;
interpreter . set ( dst ( ) , method ? : js_undefined ( ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > GetObjectPropertyIterator : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( get_object_property_iterator ( interpreter . vm ( ) , interpreter . get ( object ( ) ) ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > IteratorClose : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto & iterator = verify_cast < IteratorRecord > ( interpreter . get ( m_iterator_record ) . as_object ( ) ) ;
2023-09-27 10:10:00 +02:00
// FIXME: Return the value of the resulting completion. (Note that m_completion_value can be empty!)
TRY ( iterator_close ( vm , iterator , Completion { m_completion_type , m_completion_value , { } } ) ) ;
return { } ;
}
ThrowCompletionOr < void > AsyncIteratorClose : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto & iterator = verify_cast < IteratorRecord > ( interpreter . get ( m_iterator_record ) . as_object ( ) ) ;
2023-09-27 10:10:00 +02:00
// FIXME: Return the value of the resulting completion. (Note that m_completion_value can be empty!)
TRY ( async_iterator_close ( vm , iterator , Completion { m_completion_type , m_completion_value , { } } ) ) ;
return { } ;
}
ThrowCompletionOr < void > IteratorNext : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
auto & iterator_record = verify_cast < IteratorRecord > ( interpreter . get ( m_iterator_record ) . as_object ( ) ) ;
interpreter . set ( dst ( ) , TRY ( iterator_next ( vm , iterator_record ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > NewClass : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-02-04 08:00:54 +01:00
Value super_class ;
if ( m_super_class . has_value ( ) )
super_class = interpreter . get ( m_super_class . value ( ) ) ;
interpreter . set ( dst ( ) , TRY ( new_class ( interpreter . vm ( ) , super_class , m_class_expression , m_lhs_name ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
// 13.5.3.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-typeof-operator-runtime-semantics-evaluation
ThrowCompletionOr < void > TypeofVariable : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , TRY ( typeof_variable ( vm , interpreter . current_executable ( ) . get_identifier ( m_identifier ) ) ) ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
ThrowCompletionOr < void > BlockDeclarationInstantiation : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto old_environment = vm . running_execution_context ( ) . lexical_environment ;
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm . running_execution_context ( ) ;
running_execution_context . saved_lexical_environments . append ( old_environment ) ;
running_execution_context . lexical_environment = new_declarative_environment ( * old_environment ) ;
m_scope_node . block_declaration_instantiation ( vm , running_execution_context . lexical_environment ) ;
2023-09-27 10:10:00 +02:00
return { } ;
}
2024-02-04 08:00:54 +01:00
ByteString Mov : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " Mov {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " src " sv , m_src , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString NewArray : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
StringBuilder builder ;
2024-02-04 08:00:54 +01:00
builder . appendff ( " NewArray {} " , format_operand ( " dst " sv , dst ( ) , executable ) ) ;
2023-09-27 10:10:00 +02:00
if ( m_element_count ! = 0 ) {
2024-02-04 08:00:54 +01:00
builder . appendff ( " , [{}-{}] " , format_operand ( " from " sv , m_elements [ 0 ] , executable ) , format_operand ( " to " sv , m_elements [ 1 ] , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString NewPrimitiveArray : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-11-17 22:07:23 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " NewPrimitiveArray {}, {} " sv ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
2024-03-03 12:37:28 +01:00
format_value_list ( " elements " sv , elements ( ) ) ) ;
2023-11-17 22:07:23 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString ArrayAppend : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " Append {}, {}{} " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
format_operand ( " src " sv , src ( ) , executable ) ,
m_is_spread ? " ** " sv : " " sv ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString IteratorToArray : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " IteratorToArray {}, {} " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
format_operand ( " iterator " sv , iterator ( ) , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString NewObject : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " NewObject {} " , format_operand ( " dst " sv , dst ( ) , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString NewRegExp : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " NewRegExp {}, source:{} ( \" {} \" ) flags:{} ( \" {} \" ) " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
m_source_index , executable . get_string ( m_source_index ) , m_flags_index , executable . get_string ( m_flags_index ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString CopyObjectExcludingProperties : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
StringBuilder builder ;
2024-02-04 08:00:54 +01:00
builder . appendff ( " CopyObjectExcludingProperties {}, {} " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
format_operand ( " from " sv , m_from_object , executable ) ) ;
2023-09-27 10:10:00 +02:00
if ( m_excluded_names_count ! = 0 ) {
builder . append ( " excluding:[ " sv ) ;
2024-02-04 08:00:54 +01:00
for ( size_t i = 0 ; i < m_excluded_names_count ; + + i ) {
if ( i ! = 0 )
builder . append ( " , " sv ) ;
builder . append ( format_operand ( " # " sv , m_excluded_names [ i ] , executable ) ) ;
}
2023-09-27 10:10:00 +02:00
builder . append ( ' ] ' ) ;
}
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString ConcatString : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " ConcatString {}, {} " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
format_operand ( " src " sv , src ( ) , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString GetCalleeAndThisFromEnvironment : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetCalleeAndThisFromEnvironment {}, {} <- {} " ,
format_operand ( " callee " sv , m_callee , executable ) ,
format_operand ( " this " sv , m_this_value , executable ) ,
executable . identifier_table - > get ( m_identifier ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString GetVariable : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetVariable {}, {} " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
executable . identifier_table - > get ( m_identifier ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString GetGlobal : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetGlobal {}, {} " , format_operand ( " dst " sv , dst ( ) , executable ) ,
executable . identifier_table - > get ( m_identifier ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString DeleteVariable : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " DeleteVariable {} ({}) " , m_identifier , executable . identifier_table - > get ( m_identifier ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString CreateLexicalEnvironment : : to_byte_string_impl ( Bytecode : : Executable const & ) const
2023-09-27 10:10:00 +02:00
{
return " CreateLexicalEnvironment " sv ;
}
2023-12-16 17:49:34 +03:30
ByteString CreateVariable : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto mode_string = m_mode = = EnvironmentMode : : Lexical ? " Lexical " : " Variable " ;
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " CreateVariable env:{} immutable:{} global:{} {} ({}) " , mode_string , m_is_immutable , m_is_global , m_identifier , executable . identifier_table - > get ( m_identifier ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString EnterObjectEnvironment : : to_byte_string_impl ( Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " EnterObjectEnvironment {} " ,
format_operand ( " object " sv , m_object , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString SetVariable : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto initialization_mode_name = m_initialization_mode = = InitializationMode : : Initialize ? " Initialize " : " Set " ;
auto mode_string = m_mode = = EnvironmentMode : : Lexical ? " Lexical " : " Variable " ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " SetVariable {}, {}, env:{} init:{} " ,
executable . identifier_table - > get ( m_identifier ) ,
format_operand ( " src " sv , src ( ) , executable ) ,
mode_string , initialization_mode_name ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString SetLocal : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " SetLocal {}, {} " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
format_operand ( " src " sv , src ( ) , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
static StringView property_kind_to_string ( PropertyKind kind )
{
switch ( kind ) {
case PropertyKind : : Getter :
return " getter " sv ;
case PropertyKind : : Setter :
return " setter " sv ;
case PropertyKind : : KeyValue :
return " key-value " sv ;
case PropertyKind : : DirectKeyValue :
return " direct-key-value " sv ;
case PropertyKind : : Spread :
return " spread " sv ;
case PropertyKind : : ProtoSetter :
return " proto-setter " sv ;
}
VERIFY_NOT_REACHED ( ) ;
}
2023-12-16 17:49:34 +03:30
ByteString PutById : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto kind = property_kind_to_string ( m_kind ) ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " PutById {}, {}, {}, kind:{} " ,
format_operand ( " base " sv , m_base , executable ) ,
executable . identifier_table - > get ( m_property ) ,
format_operand ( " src " sv , m_src , executable ) ,
kind ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString PutByIdWithThis : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto kind = property_kind_to_string ( m_kind ) ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " PutByIdWithThis {}, {}, {}, {}, kind:{} " ,
format_operand ( " base " sv , m_base , executable ) ,
executable . identifier_table - > get ( m_property ) ,
format_operand ( " src " sv , m_src , executable ) ,
format_operand ( " this " sv , m_this_value , executable ) ,
kind ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString PutPrivateById : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto kind = property_kind_to_string ( m_kind ) ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted (
" PutPrivateById {}, {}, {}, kind:{} " ,
format_operand ( " base " sv , m_base , executable ) ,
executable . identifier_table - > get ( m_property ) ,
format_operand ( " src " sv , m_src , executable ) ,
kind ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString GetById : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetById {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
executable . identifier_table - > get ( m_property ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString GetByIdWithThis : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetByIdWithThis {}, {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
executable . identifier_table - > get ( m_property ) ,
format_operand ( " this " sv , m_this_value , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString GetPrivateById : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetPrivateById {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
executable . identifier_table - > get ( m_property ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString HasPrivateId : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " HasPrivateId {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
executable . identifier_table - > get ( m_property ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString DeleteById : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " DeleteById {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
executable . identifier_table - > get ( m_property ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString DeleteByIdWithThis : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " DeleteByIdWithThis {}, {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
executable . identifier_table - > get ( m_property ) ,
format_operand ( " this " sv , m_this_value , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString Jump : : to_byte_string_impl ( Bytecode : : Executable const & ) const
2023-09-27 10:10:00 +02:00
{
if ( m_true_target . has_value ( ) )
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " Jump {} " , * m_true_target ) ;
return ByteString : : formatted ( " Jump <empty> " ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString JumpIf : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2023-12-16 17:49:34 +03:30
auto true_string = m_true_target . has_value ( ) ? ByteString : : formatted ( " {} " , * m_true_target ) : " <empty> " ;
auto false_string = m_false_target . has_value ( ) ? ByteString : : formatted ( " {} " , * m_false_target ) : " <empty> " ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " JumpIf {}, \033 [32mtrue \033 [0m:{} \033 [32mfalse \033 [0m:{} " ,
format_operand ( " condition " sv , m_condition , executable ) ,
true_string , false_string ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString JumpNullish : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2023-12-16 17:49:34 +03:30
auto true_string = m_true_target . has_value ( ) ? ByteString : : formatted ( " {} " , * m_true_target ) : " <empty> " ;
auto false_string = m_false_target . has_value ( ) ? ByteString : : formatted ( " {} " , * m_false_target ) : " <empty> " ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " JumpNullish {}, null:{} nonnull:{} " ,
format_operand ( " condition " sv , m_condition , executable ) ,
true_string , false_string ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString JumpUndefined : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2023-12-16 17:49:34 +03:30
auto true_string = m_true_target . has_value ( ) ? ByteString : : formatted ( " {} " , * m_true_target ) : " <empty> " ;
auto false_string = m_false_target . has_value ( ) ? ByteString : : formatted ( " {} " , * m_false_target ) : " <empty> " ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " JumpUndefined {}, undefined:{} defined:{} " ,
format_operand ( " condition " sv , m_condition , executable ) ,
true_string , false_string ) ;
2023-09-27 10:10:00 +02:00
}
static StringView call_type_to_string ( CallType type )
{
switch ( type ) {
case CallType : : Call :
return " " sv ;
case CallType : : Construct :
return " (Construct) " sv ;
case CallType : : DirectEval :
return " (DirectEval) " sv ;
}
VERIFY_NOT_REACHED ( ) ;
}
2023-12-16 17:49:34 +03:30
ByteString Call : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto type = call_type_to_string ( m_type ) ;
2024-02-20 15:59:45 +01:00
StringBuilder builder ;
builder . appendff ( " Call{} {}, {}, {} " sv ,
type ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " callee " sv , m_callee , executable ) ,
format_operand ( " this " sv , m_this_value , executable ) ) ;
builder . append ( format_operand_list ( " args " sv , { m_arguments , m_argument_count } , executable ) ) ;
2024-02-04 08:00:54 +01:00
if ( m_builtin . has_value ( ) ) {
2024-02-20 15:59:45 +01:00
builder . appendff ( " , (builtin:{}) " , m_builtin . value ( ) ) ;
2024-02-04 08:00:54 +01:00
}
2024-02-20 15:59:45 +01:00
2024-02-04 08:00:54 +01:00
if ( m_expression_string . has_value ( ) ) {
2024-02-20 15:59:45 +01:00
builder . appendff ( " , `{}` " , executable . get_string ( m_expression_string . value ( ) ) ) ;
2024-02-04 08:00:54 +01:00
}
2024-02-20 15:59:45 +01:00
return builder . to_byte_string ( ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString CallWithArgumentArray : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto type = call_type_to_string ( m_type ) ;
2024-02-04 08:00:54 +01:00
StringBuilder builder ;
builder . appendff ( " CallWithArgumentArray{} {}, {}, {}, {} " ,
type ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " callee " sv , m_callee , executable ) ,
format_operand ( " this " sv , m_this_value , executable ) ,
format_operand ( " arguments " sv , m_arguments , executable ) ) ;
2023-09-27 10:10:00 +02:00
if ( m_expression_string . has_value ( ) )
2024-02-04 08:00:54 +01:00
builder . appendff ( " ({}) " , executable . get_string ( m_expression_string . value ( ) ) ) ;
return builder . to_byte_string ( ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString SuperCallWithArgumentArray : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " SuperCallWithArgumentArray {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " arguments " sv , m_arguments , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString NewFunction : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
StringBuilder builder ;
2024-02-04 08:00:54 +01:00
builder . appendff ( " NewFunction {} " ,
format_operand ( " dst " sv , m_dst , executable ) ) ;
2023-09-27 10:10:00 +02:00
if ( m_function_node . has_name ( ) )
builder . appendff ( " name:{} " sv , m_function_node . name ( ) ) ;
if ( m_lhs_name . has_value ( ) )
2024-02-04 08:00:54 +01:00
builder . appendff ( " lhs_name:{} " sv , executable . get_identifier ( m_lhs_name . value ( ) ) ) ;
2023-09-27 10:10:00 +02:00
if ( m_home_object . has_value ( ) )
2024-02-04 08:00:54 +01:00
builder . appendff ( " , {} " sv , format_operand ( " home_object " sv , m_home_object . value ( ) , executable ) ) ;
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString NewClass : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
StringBuilder builder ;
auto name = m_class_expression . name ( ) ;
2024-02-04 08:00:54 +01:00
builder . appendff ( " NewClass {} " ,
format_operand ( " dst " sv , m_dst , executable ) ) ;
if ( m_super_class . has_value ( ) )
builder . appendff ( " , {} " , format_operand ( " super_class " sv , * m_super_class , executable ) ) ;
if ( ! name . is_empty ( ) )
builder . appendff ( " , {} " , name ) ;
2023-09-27 10:10:00 +02:00
if ( m_lhs_name . has_value ( ) )
2024-02-04 08:00:54 +01:00
builder . appendff ( " , lhs_name:{} " sv , m_lhs_name . value ( ) ) ;
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString Return : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
if ( m_value . has_value ( ) )
return ByteString : : formatted ( " Return {} " , format_operand ( " value " sv , m_value . value ( ) , executable ) ) ;
2023-09-27 10:10:00 +02:00
return " Return " ;
}
2024-02-04 08:00:54 +01:00
ByteString Increment : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " Increment {} " , format_operand ( " dst " sv , m_dst , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-20 11:45:01 +01:00
ByteString PostfixIncrement : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " PostfixIncrement {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
2024-03-03 09:04:30 +01:00
format_operand ( " src " sv , m_src , executable ) ) ;
2024-02-20 11:45:01 +01:00
}
ByteString Decrement : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " Decrement {} " , format_operand ( " dst " sv , m_dst , executable ) ) ;
}
ByteString PostfixDecrement : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-20 11:45:01 +01:00
return ByteString : : formatted ( " PostfixDecrement {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
2024-03-03 09:04:30 +01:00
format_operand ( " src " sv , m_src , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString Throw : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " Throw {} " ,
format_operand ( " src " sv , m_src , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString ThrowIfNotObject : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " ThrowIfNotObject {} " ,
format_operand ( " src " sv , m_src , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString ThrowIfNullish : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " ThrowIfNullish {} " ,
format_operand ( " src " sv , m_src , executable ) ) ;
}
ByteString ThrowIfTDZ : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " ThrowIfTDZ {} " ,
format_operand ( " src " sv , m_src , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString EnterUnwindContext : : to_byte_string_impl ( Bytecode : : Executable const & ) const
2023-09-27 10:10:00 +02:00
{
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " EnterUnwindContext entry:{} " , m_entry_point ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString ScheduleJump : : to_byte_string_impl ( Bytecode : : Executable const & ) const
2023-09-27 10:10:00 +02:00
{
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " ScheduleJump {} " , m_target ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString LeaveLexicalEnvironment : : to_byte_string_impl ( Bytecode : : Executable const & ) const
2023-09-27 10:10:00 +02:00
{
return " LeaveLexicalEnvironment " sv ;
}
2023-12-16 17:49:34 +03:30
ByteString LeaveUnwindContext : : to_byte_string_impl ( Bytecode : : Executable const & ) const
2023-09-27 10:10:00 +02:00
{
return " LeaveUnwindContext " ;
}
2023-12-16 17:49:34 +03:30
ByteString ContinuePendingUnwind : : to_byte_string_impl ( Bytecode : : Executable const & ) const
2023-09-27 10:10:00 +02:00
{
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " ContinuePendingUnwind resume:{} " , m_resume_target ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString Yield : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
if ( m_continuation_label . has_value ( ) ) {
return ByteString : : formatted ( " Yield continuation:@{}, {} " ,
m_continuation_label - > block ( ) . name ( ) ,
format_operand ( " value " sv , m_value , executable ) ) ;
}
return ByteString : : formatted ( " Yield return {} " ,
format_operand ( " value " sv , m_value , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString Await : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " Await {}, continuation:@{} " ,
format_operand ( " argument " sv , m_argument , executable ) ,
m_continuation_label . block ( ) . name ( ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString GetByValue : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetByValue {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
format_operand ( " property " sv , m_property , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString GetByValueWithThis : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetByValueWithThis {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
format_operand ( " property " sv , m_property , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString PutByValue : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto kind = property_kind_to_string ( m_kind ) ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " PutByValue {}, {}, {}, kind:{} " ,
format_operand ( " base " sv , m_base , executable ) ,
format_operand ( " property " sv , m_property , executable ) ,
format_operand ( " src " sv , m_src , executable ) ,
kind ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString PutByValueWithThis : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto kind = property_kind_to_string ( m_kind ) ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " PutByValueWithThis {}, {}, {}, {}, kind:{} " ,
format_operand ( " base " sv , m_base , executable ) ,
format_operand ( " property " sv , m_property , executable ) ,
format_operand ( " src " sv , m_src , executable ) ,
format_operand ( " this " sv , m_this_value , executable ) ,
kind ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString DeleteByValue : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " DeleteByValue {}, {}, {} " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
format_operand ( " property " sv , m_property , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString DeleteByValueWithThis : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " DeleteByValueWithThis {}, {}, {}, {} " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
format_operand ( " property " sv , m_property , executable ) ,
format_operand ( " this " sv , m_this_value , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString GetIterator : : to_byte_string_impl ( Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
auto hint = m_hint = = IteratorHint : : Sync ? " sync " : " async " ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetIterator {}, {}, hint:{} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " iterable " sv , m_iterable , executable ) ,
hint ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString GetMethod : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetMethod {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " object " sv , m_object , executable ) ,
executable . identifier_table - > get ( m_property ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString GetObjectPropertyIterator : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetObjectPropertyIterator {}, {} " ,
format_operand ( " dst " sv , dst ( ) , executable ) ,
format_operand ( " object " sv , object ( ) , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString IteratorClose : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
if ( ! m_completion_value . has_value ( ) )
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " IteratorClose {}, completion_type={} completion_value=<empty> " ,
format_operand ( " iterator_record " sv , m_iterator_record , executable ) ,
to_underlying ( m_completion_type ) ) ;
2023-09-27 10:10:00 +02:00
auto completion_value_string = m_completion_value - > to_string_without_side_effects ( ) ;
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " IteratorClose {}, completion_type={} completion_value={} " ,
format_operand ( " iterator_record " sv , m_iterator_record , executable ) ,
to_underlying ( m_completion_type ) , completion_value_string ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString AsyncIteratorClose : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
if ( ! m_completion_value . has_value ( ) ) {
return ByteString : : formatted ( " AsyncIteratorClose {}, completion_type:{} completion_value:<empty> " ,
format_operand ( " iterator_record " sv , m_iterator_record , executable ) ,
to_underlying ( m_completion_type ) ) ;
}
2023-09-27 10:10:00 +02:00
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " AsyncIteratorClose {}, completion_type:{}, completion_value:{} " ,
format_operand ( " iterator_record " sv , m_iterator_record , executable ) ,
to_underlying ( m_completion_type ) , m_completion_value ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString IteratorNext : : to_byte_string_impl ( Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " IteratorNext {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " iterator_record " sv , m_iterator_record , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString ResolveThisBinding : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " ResolveThisBinding {} " , format_operand ( " dst " sv , m_dst , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString ResolveSuperBase : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " ResolveSuperBase {} " ,
format_operand ( " dst " sv , m_dst , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString GetNewTarget : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetNewTarget {} " , format_operand ( " dst " sv , m_dst , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString GetImportMeta : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetImportMeta {} " , format_operand ( " dst " sv , m_dst , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2023-12-16 17:49:34 +03:30
ByteString TypeofVariable : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " TypeofVariable {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
executable . identifier_table - > get ( m_identifier ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString BlockDeclarationInstantiation : : to_byte_string_impl ( Bytecode : : Executable const & ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return " BlockDeclarationInstantiation " sv ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString ImportCall : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " ImportCall {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " specifier " sv , m_specifier , executable ) ,
format_operand ( " options " sv , m_options , executable ) ) ;
}
ByteString Catch : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " Catch {} " ,
format_operand ( " dst " sv , m_dst , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-04-11 11:58:18 +02:00
ByteString LeaveFinally : : to_byte_string_impl ( Bytecode : : Executable const & ) const
{
return ByteString : : formatted ( " LeaveFinally " ) ;
}
2024-04-11 11:07:35 +02:00
ByteString RestoreScheduledJump : : to_byte_string_impl ( Bytecode : : Executable const & ) const
{
return ByteString : : formatted ( " RestoreScheduledJump " ) ;
}
2024-02-04 08:00:54 +01:00
ByteString GetObjectFromIteratorRecord : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetObjectFromIteratorRecord {}, {} " ,
format_operand ( " object " sv , m_object , executable ) ,
format_operand ( " iterator_record " sv , m_iterator_record , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
ByteString GetNextMethodFromIteratorRecord : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-11-11 23:19:46 +01:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " GetNextMethodFromIteratorRecord {}, {} " ,
format_operand ( " next_method " sv , m_next_method , executable ) ,
format_operand ( " iterator_record " sv , m_iterator_record , executable ) ) ;
2023-11-11 23:19:46 +01:00
}
2024-02-04 08:00:54 +01:00
ByteString End : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-12-07 10:44:41 +01:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " End {} " , format_operand ( " value " sv , m_value , executable ) ) ;
2023-12-07 10:44:41 +01:00
}
2024-02-04 08:00:54 +01:00
ByteString Dump : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-12-07 10:44:41 +01:00
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " Dump '{}', {} " , m_text ,
format_operand ( " value " sv , m_value , executable ) ) ;
2023-12-07 10:44:41 +01:00
}
2023-09-27 10:10:00 +02:00
}