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 ) ;
2024-05-12 18:49:03 +02:00
auto value = executable . constants [ operand . index ( ) - executable . number_of_registers ] ;
2024-02-04 08:00:54 +01:00
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-05-08 12:43:08 +02: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 ( ) )
2024-05-06 13:50:21 +02:00
builder . appendff ( " \033 [32m{} \033 [0m:[ " , name ) ;
2024-03-03 12:37:28 +01:00
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
{
2024-05-12 18:49:03 +02:00
return m_registers_and_constants_and_locals . data ( ) [ op . index ( ) ] ;
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
{
2024-05-12 18:49:03 +02:00
m_registers_and_constants_and_locals . data ( ) [ op . index ( ) ] = value ;
2024-02-02 10:19:17 +01:00
}
2024-05-18 17:25:43 +02:00
ALWAYS_INLINE Value Interpreter : : do_yield ( Value value , Optional < Label > continuation )
{
auto object = Object : : create ( realm ( ) , nullptr ) ;
object - > define_direct_property ( " result " , value , JS : : default_attributes ) ;
if ( continuation . 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 ( continuation - > address ( ) ) , JS : : default_attributes ) ;
else
object - > define_direct_property ( " continuation " , js_null ( ) , JS : : default_attributes ) ;
object - > define_direct_property ( " isAwait " , Value ( false ) , JS : : default_attributes ) ;
return object ;
}
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.
2024-05-31 15:12:33 +02:00
auto script_context = ExecutionContext : : create ( ) ;
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-05-05 22:06:55 +02:00
auto executable_result = JS : : Bytecode : : Generator : : generate_from_ast_node ( 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-06 06:44:08 +02:00
auto result_or_error = run_executable ( * executable , { } , { } ) ;
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-05-06 06:44:08 +02:00
Interpreter : : HandleExceptionResponse Interpreter : : handle_exception ( size_t & program_counter , Value exception )
2021-06-03 10:46:30 +02:00
{
2024-05-06 06:44:08 +02:00
reg ( Register : : exception ( ) ) = exception ;
m_scheduled_jump = { } ;
auto handlers = current_executable ( ) . exception_handlers_for_offset ( program_counter ) ;
if ( ! handlers . has_value ( ) ) {
return HandleExceptionResponse : : ExitFromExecutable ;
}
auto & handler = handlers - > handler_offset ;
auto & finalizer = handlers - > finalizer_offset ;
2024-05-11 18:16:27 +02:00
VERIFY ( ! running_execution_context ( ) . unwind_contexts . is_empty ( ) ) ;
auto & unwind_context = running_execution_context ( ) . unwind_contexts . last ( ) ;
2024-05-06 06:44:08 +02:00
VERIFY ( unwind_context . executable = = m_current_executable ) ;
if ( handler . has_value ( ) ) {
program_counter = handler . value ( ) ;
return HandleExceptionResponse : : ContinueInThisExecutable ;
}
if ( finalizer . has_value ( ) ) {
program_counter = finalizer . value ( ) ;
return HandleExceptionResponse : : ContinueInThisExecutable ;
}
VERIFY_NOT_REACHED ( ) ;
}
2024-05-06 16:50:48 +02:00
// FIXME: GCC takes a *long* time to compile with flattening, and it will time out our CI. :|
# if defined(AK_COMPILER_CLANG)
# define FLATTEN_ON_CLANG FLATTEN
# else
# define FLATTEN_ON_CLANG
# endif
FLATTEN_ON_CLANG void Interpreter : : run_bytecode ( size_t entry_point )
2024-05-06 06:44:08 +02:00
{
2024-05-07 07:50:19 +02:00
if ( vm ( ) . did_reach_stack_space_limit ( ) ) {
reg ( Register : : exception ( ) ) = vm ( ) . throw_completion < InternalError > ( ErrorType : : CallStackSizeExceeded ) . release_value ( ) . value ( ) ;
return ;
}
2024-05-11 18:16:27 +02:00
auto & running_execution_context = this - > running_execution_context ( ) ;
2024-05-05 22:06:55 +02:00
auto * arguments = running_execution_context . arguments . data ( ) ;
2023-09-27 10:31:07 +02:00
auto & accumulator = this - > accumulator ( ) ;
2024-05-06 06:44:08 +02:00
auto & executable = current_executable ( ) ;
auto const * bytecode = executable . bytecode . data ( ) ;
size_t program_counter = entry_point ;
TemporaryChange change ( m_program_counter , Optional < size_t & > ( program_counter ) ) ;
2024-05-06 16:44:45 +02:00
// Declare a lookup table for computed goto with each of the `handle_*` labels
// to avoid the overhead of a switch statement.
// This is a GCC extension, but it's also supported by Clang.
static void * const bytecode_dispatch_table [ ] = {
# define SET_UP_LABEL(name) &&handle_##name,
ENUMERATE_BYTECODE_OPS ( SET_UP_LABEL )
} ;
2024-05-09 15:13:31 +02:00
# undef SET_UP_LABEL
2024-05-06 16:44:45 +02:00
# define DISPATCH_NEXT(name) \
do { \
if constexpr ( Op : : name : : IsVariableLength ) \
program_counter + = instruction . length ( ) ; \
else \
program_counter + = sizeof ( Op : : name ) ; \
auto & next_instruction = * reinterpret_cast < Instruction const * > ( & bytecode [ program_counter ] ) ; \
goto * bytecode_dispatch_table [ static_cast < size_t > ( next_instruction . type ( ) ) ] ; \
} while ( 0 )
2021-06-09 06:49:58 +04:30
for ( ; ; ) {
2023-09-26 16:45:55 +02:00
start :
2024-05-06 06:44:08 +02:00
for ( ; ; ) {
2024-05-06 16:44:45 +02:00
goto * bytecode_dispatch_table [ static_cast < size_t > ( ( * reinterpret_cast < Instruction const * > ( & bytecode [ program_counter ] ) ) . type ( ) ) ] ;
2023-09-26 17:14:59 +02:00
2024-05-05 22:06:55 +02:00
handle_GetArgument : {
auto const & instruction = * reinterpret_cast < Op : : GetArgument const * > ( & bytecode [ program_counter ] ) ;
set ( instruction . dst ( ) , arguments [ instruction . index ( ) ] ) ;
DISPATCH_NEXT ( GetArgument ) ;
}
handle_SetArgument : {
auto const & instruction = * reinterpret_cast < Op : : SetArgument const * > ( & bytecode [ program_counter ] ) ;
arguments [ instruction . index ( ) ] = get ( instruction . src ( ) ) ;
DISPATCH_NEXT ( SetArgument ) ;
}
2024-05-06 16:44:45 +02:00
handle_Mov : {
auto & instruction = * reinterpret_cast < Op : : Mov const * > ( & bytecode [ program_counter ] ) ;
set ( instruction . dst ( ) , get ( instruction . src ( ) ) ) ;
DISPATCH_NEXT ( Mov ) ;
}
handle_End : {
auto & instruction = * reinterpret_cast < Op : : End const * > ( & bytecode [ program_counter ] ) ;
accumulator = get ( instruction . value ( ) ) ;
return ;
}
handle_Jump : {
auto & instruction = * reinterpret_cast < Op : : Jump const * > ( & bytecode [ program_counter ] ) ;
program_counter = instruction . target ( ) . address ( ) ;
goto start ;
}
handle_JumpIf : {
auto & instruction = * reinterpret_cast < Op : : JumpIf const * > ( & bytecode [ program_counter ] ) ;
if ( get ( instruction . condition ( ) ) . to_boolean ( ) )
program_counter = instruction . true_target ( ) . address ( ) ;
else
program_counter = instruction . false_target ( ) . address ( ) ;
goto start ;
}
handle_JumpTrue : {
auto & instruction = * reinterpret_cast < Op : : JumpTrue const * > ( & bytecode [ program_counter ] ) ;
if ( get ( instruction . condition ( ) ) . to_boolean ( ) ) {
program_counter = instruction . target ( ) . address ( ) ;
2024-05-06 10:42:52 +02:00
goto start ;
2024-05-06 10:15:17 +02:00
}
2024-05-06 16:44:45 +02:00
DISPATCH_NEXT ( JumpTrue ) ;
}
handle_JumpFalse : {
auto & instruction = * reinterpret_cast < Op : : JumpFalse const * > ( & bytecode [ program_counter ] ) ;
if ( ! get ( instruction . condition ( ) ) . to_boolean ( ) ) {
program_counter = instruction . target ( ) . address ( ) ;
2024-05-06 10:42:52 +02:00
goto start ;
2024-05-06 10:15:17 +02:00
}
2024-05-06 16:44:45 +02:00
DISPATCH_NEXT ( JumpFalse ) ;
}
handle_JumpNullish : {
auto & instruction = * reinterpret_cast < Op : : JumpNullish const * > ( & bytecode [ program_counter ] ) ;
if ( get ( instruction . condition ( ) ) . is_nullish ( ) )
program_counter = instruction . true_target ( ) . address ( ) ;
else
program_counter = instruction . false_target ( ) . address ( ) ;
goto start ;
}
2024-05-13 09:23:53 +02:00
# define HANDLE_COMPARISON_OP(op_TitleCase, op_snake_case, numeric_operator) \
2024-05-10 11:22:27 +02:00
handle_Jump # # op_TitleCase : \
{ \
auto & instruction = * reinterpret_cast < Op : : Jump # # op_TitleCase const * > ( & bytecode [ program_counter ] ) ; \
2024-05-13 09:23:53 +02:00
auto lhs = get ( instruction . lhs ( ) ) ; \
auto rhs = get ( instruction . rhs ( ) ) ; \
if ( lhs . is_number ( ) & & rhs . is_number ( ) ) { \
bool result ; \
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) { \
result = lhs . as_i32 ( ) numeric_operator rhs . as_i32 ( ) ; \
} else { \
result = lhs . as_double ( ) numeric_operator rhs . as_double ( ) ; \
} \
program_counter = result ? instruction . true_target ( ) . address ( ) : instruction . false_target ( ) . address ( ) ; \
goto start ; \
} \
2024-05-10 11:22:27 +02:00
auto result = op_snake_case ( vm ( ) , get ( instruction . lhs ( ) ) , get ( instruction . rhs ( ) ) ) ; \
if ( result . is_error ( ) ) { \
if ( handle_exception ( program_counter , result . error_value ( ) ) = = HandleExceptionResponse : : ExitFromExecutable ) \
return ; \
goto start ; \
} \
if ( result . value ( ) . to_boolean ( ) ) \
program_counter = instruction . true_target ( ) . address ( ) ; \
else \
program_counter = instruction . false_target ( ) . address ( ) ; \
goto start ; \
2024-05-09 15:13:31 +02:00
}
JS_ENUMERATE_COMPARISON_OPS ( HANDLE_COMPARISON_OP )
# undef HANDLE_COMPARISON_OP
2024-05-06 16:44:45 +02:00
handle_JumpUndefined : {
auto & instruction = * reinterpret_cast < Op : : JumpUndefined const * > ( & bytecode [ program_counter ] ) ;
if ( get ( instruction . condition ( ) ) . is_undefined ( ) )
program_counter = instruction . true_target ( ) . address ( ) ;
else
program_counter = instruction . false_target ( ) . address ( ) ;
goto start ;
}
handle_EnterUnwindContext : {
auto & instruction = * reinterpret_cast < Op : : EnterUnwindContext const * > ( & bytecode [ program_counter ] ) ;
enter_unwind_context ( ) ;
program_counter = instruction . entry_point ( ) . address ( ) ;
goto start ;
}
handle_ContinuePendingUnwind : {
auto & instruction = * reinterpret_cast < Op : : ContinuePendingUnwind const * > ( & bytecode [ program_counter ] ) ;
if ( auto exception = reg ( Register : : exception ( ) ) ; ! exception . is_empty ( ) ) {
if ( handle_exception ( program_counter , exception ) = = HandleExceptionResponse : : ExitFromExecutable )
return ;
2023-09-26 19:43:44 +02:00
goto start ;
2024-05-05 11:52:14 +02:00
}
2024-05-06 16:44:45 +02:00
if ( ! saved_return_value ( ) . is_empty ( ) ) {
do_return ( saved_return_value ( ) ) ;
2024-05-12 11:03:26 +02:00
if ( auto handlers = executable . exception_handlers_for_offset ( program_counter ) ; handlers . has_value ( ) ) {
if ( auto finalizer = handlers . value ( ) . finalizer_offset ; finalizer . has_value ( ) ) {
VERIFY ( ! running_execution_context . unwind_contexts . is_empty ( ) ) ;
auto & unwind_context = running_execution_context . unwind_contexts . last ( ) ;
VERIFY ( unwind_context . executable = = m_current_executable ) ;
reg ( Register : : saved_return_value ( ) ) = reg ( Register : : return_value ( ) ) ;
reg ( Register : : return_value ( ) ) = { } ;
program_counter = finalizer . value ( ) ;
// the unwind_context will be pop'ed when entering the finally block
goto start ;
}
}
return ;
2024-05-05 11:52:14 +02:00
}
2024-05-06 16:44:45 +02:00
auto const old_scheduled_jump = running_execution_context . previously_scheduled_jumps . take_last ( ) ;
if ( m_scheduled_jump . has_value ( ) ) {
program_counter = m_scheduled_jump . value ( ) ;
m_scheduled_jump = { } ;
} else {
program_counter = instruction . resume_target ( ) . address ( ) ;
// set the scheduled jump to the old value if we continue
// where we left it
m_scheduled_jump = old_scheduled_jump ;
2023-10-21 22:46:40 +02:00
}
2024-05-06 16:44:45 +02:00
goto start ;
}
handle_ScheduleJump : {
auto & instruction = * reinterpret_cast < Op : : ScheduleJump const * > ( & bytecode [ program_counter ] ) ;
m_scheduled_jump = instruction . target ( ) . address ( ) ;
auto finalizer = executable . exception_handlers_for_offset ( program_counter ) . value ( ) . finalizer_offset ;
VERIFY ( finalizer . has_value ( ) ) ;
program_counter = finalizer . value ( ) ;
goto start ;
}
2024-05-10 11:22:27 +02:00
# define HANDLE_INSTRUCTION(name) \
handle_ # # name : \
{ \
auto & instruction = * reinterpret_cast < Op : : name const * > ( & bytecode [ program_counter ] ) ; \
{ \
auto result = instruction . execute_impl ( * this ) ; \
if ( result . is_error ( ) ) { \
if ( handle_exception ( program_counter , result . error_value ( ) ) = = HandleExceptionResponse : : ExitFromExecutable ) \
return ; \
goto start ; \
} \
} \
DISPATCH_NEXT ( name ) ; \
2024-05-06 16:44:45 +02:00
}
2024-05-09 15:24:34 +02:00
# define HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK(name) \
handle_ # # name : \
{ \
auto & instruction = * reinterpret_cast < Op : : name const * > ( & bytecode [ program_counter ] ) ; \
2024-05-12 10:47:52 +02:00
instruction . execute_impl ( * this ) ; \
2024-05-09 15:24:34 +02:00
DISPATCH_NEXT ( name ) ; \
}
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( Add ) ;
2024-05-11 22:54:41 +00:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( AddPrivateName ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( ArrayAppend ) ;
HANDLE_INSTRUCTION ( AsyncIteratorClose ) ;
HANDLE_INSTRUCTION ( BitwiseAnd ) ;
HANDLE_INSTRUCTION ( BitwiseNot ) ;
HANDLE_INSTRUCTION ( BitwiseOr ) ;
HANDLE_INSTRUCTION ( BitwiseXor ) ;
2024-05-09 15:24:34 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( BlockDeclarationInstantiation ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( Call ) ;
HANDLE_INSTRUCTION ( CallWithArgumentArray ) ;
2024-05-09 15:24:34 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( Catch ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( ConcatString ) ;
HANDLE_INSTRUCTION ( CopyObjectExcludingProperties ) ;
2024-05-09 15:24:34 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( CreateLexicalEnvironment ) ;
2024-05-05 22:06:55 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( CreateVariableEnvironment ) ;
2024-05-11 22:54:41 +00:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( CreatePrivateEnvironment ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( CreateVariable ) ;
2024-05-05 22:06:55 +02:00
HANDLE_INSTRUCTION ( CreateRestParams ) ;
HANDLE_INSTRUCTION ( CreateArguments ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( Decrement ) ;
HANDLE_INSTRUCTION ( DeleteById ) ;
HANDLE_INSTRUCTION ( DeleteByIdWithThis ) ;
HANDLE_INSTRUCTION ( DeleteByValue ) ;
HANDLE_INSTRUCTION ( DeleteByValueWithThis ) ;
HANDLE_INSTRUCTION ( DeleteVariable ) ;
HANDLE_INSTRUCTION ( Div ) ;
2024-05-09 15:24:34 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( Dump ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( EnterObjectEnvironment ) ;
HANDLE_INSTRUCTION ( Exp ) ;
HANDLE_INSTRUCTION ( GetById ) ;
HANDLE_INSTRUCTION ( GetByIdWithThis ) ;
HANDLE_INSTRUCTION ( GetByValue ) ;
HANDLE_INSTRUCTION ( GetByValueWithThis ) ;
HANDLE_INSTRUCTION ( GetCalleeAndThisFromEnvironment ) ;
HANDLE_INSTRUCTION ( GetGlobal ) ;
2024-05-09 15:24:34 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( GetImportMeta ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( GetIterator ) ;
2024-05-20 11:53:28 +02:00
HANDLE_INSTRUCTION ( GetLength ) ;
HANDLE_INSTRUCTION ( GetLengthWithThis ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( GetMethod ) ;
2024-05-09 15:24:34 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( GetNewTarget ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( GetNextMethodFromIteratorRecord ) ;
HANDLE_INSTRUCTION ( GetObjectFromIteratorRecord ) ;
HANDLE_INSTRUCTION ( GetObjectPropertyIterator ) ;
HANDLE_INSTRUCTION ( GetPrivateById ) ;
2024-05-14 11:32:04 +02:00
HANDLE_INSTRUCTION ( GetBinding ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( GreaterThan ) ;
HANDLE_INSTRUCTION ( GreaterThanEquals ) ;
HANDLE_INSTRUCTION ( HasPrivateId ) ;
HANDLE_INSTRUCTION ( ImportCall ) ;
HANDLE_INSTRUCTION ( In ) ;
HANDLE_INSTRUCTION ( Increment ) ;
2024-05-14 11:30:30 +02:00
HANDLE_INSTRUCTION ( InitializeLexicalBinding ) ;
HANDLE_INSTRUCTION ( InitializeVariableBinding ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( InstanceOf ) ;
HANDLE_INSTRUCTION ( IteratorClose ) ;
HANDLE_INSTRUCTION ( IteratorNext ) ;
HANDLE_INSTRUCTION ( IteratorToArray ) ;
2024-05-09 15:24:34 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( LeaveFinally ) ;
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( LeaveLexicalEnvironment ) ;
2024-05-11 22:54:41 +00:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( LeavePrivateEnvironment ) ;
2024-05-10 17:32:19 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( LeaveUnwindContext ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( LeftShift ) ;
HANDLE_INSTRUCTION ( LessThan ) ;
HANDLE_INSTRUCTION ( LessThanEquals ) ;
HANDLE_INSTRUCTION ( LooselyEquals ) ;
HANDLE_INSTRUCTION ( LooselyInequals ) ;
HANDLE_INSTRUCTION ( Mod ) ;
HANDLE_INSTRUCTION ( Mul ) ;
2024-05-09 15:24:34 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( NewArray ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( NewClass ) ;
2024-05-09 15:24:34 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( NewFunction ) ;
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( NewObject ) ;
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( NewPrimitiveArray ) ;
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( NewRegExp ) ;
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( NewTypeError ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( Not ) ;
2024-05-18 17:25:43 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( PrepareYield ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( PostfixDecrement ) ;
HANDLE_INSTRUCTION ( PostfixIncrement ) ;
HANDLE_INSTRUCTION ( PutById ) ;
HANDLE_INSTRUCTION ( PutByIdWithThis ) ;
HANDLE_INSTRUCTION ( PutByValue ) ;
HANDLE_INSTRUCTION ( PutByValueWithThis ) ;
HANDLE_INSTRUCTION ( PutPrivateById ) ;
HANDLE_INSTRUCTION ( ResolveSuperBase ) ;
HANDLE_INSTRUCTION ( ResolveThisBinding ) ;
2024-05-10 17:32:19 +02:00
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK ( RestoreScheduledJump ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( RightShift ) ;
2024-05-14 11:30:30 +02:00
HANDLE_INSTRUCTION ( SetLexicalBinding ) ;
HANDLE_INSTRUCTION ( SetVariableBinding ) ;
2024-05-06 16:44:45 +02:00
HANDLE_INSTRUCTION ( StrictlyEquals ) ;
HANDLE_INSTRUCTION ( StrictlyInequals ) ;
HANDLE_INSTRUCTION ( Sub ) ;
HANDLE_INSTRUCTION ( SuperCallWithArgumentArray ) ;
HANDLE_INSTRUCTION ( Throw ) ;
HANDLE_INSTRUCTION ( ThrowIfNotObject ) ;
HANDLE_INSTRUCTION ( ThrowIfNullish ) ;
HANDLE_INSTRUCTION ( ThrowIfTDZ ) ;
HANDLE_INSTRUCTION ( Typeof ) ;
HANDLE_INSTRUCTION ( TypeofVariable ) ;
HANDLE_INSTRUCTION ( UnaryMinus ) ;
HANDLE_INSTRUCTION ( UnaryPlus ) ;
HANDLE_INSTRUCTION ( UnsignedRightShift ) ;
handle_Await : {
auto & instruction = * reinterpret_cast < Op : : Await const * > ( & bytecode [ program_counter ] ) ;
2024-05-12 10:47:52 +02:00
instruction . execute_impl ( * this ) ;
2024-05-12 11:03:26 +02:00
return ;
2024-05-06 16:44:45 +02:00
}
2024-05-06 10:42:52 +02:00
2024-05-06 16:44:45 +02:00
handle_Return : {
auto & instruction = * reinterpret_cast < Op : : Return const * > ( & bytecode [ program_counter ] ) ;
2024-05-12 10:47:52 +02:00
instruction . execute_impl ( * this ) ;
2024-05-12 11:03:26 +02:00
return ;
2024-05-06 16:44:45 +02:00
}
2023-09-26 19:43:44 +02:00
2024-05-06 16:44:45 +02:00
handle_Yield : {
auto & instruction = * reinterpret_cast < Op : : Yield const * > ( & bytecode [ program_counter ] ) ;
2024-05-12 10:47:52 +02:00
instruction . execute_impl ( * this ) ;
2024-05-10 07:56:39 +02: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
2024-05-12 11:03:26 +02:00
return ;
2024-05-06 16:44:45 +02:00
}
2024-05-06 06:44:08 +02:00
}
2021-06-04 12:07:38 +02:00
}
2023-09-26 16:41:42 +02:00
}
2024-05-06 06:44:08 +02:00
Interpreter : : ResultAndReturnRegister Interpreter : : run_executable ( Executable & executable , Optional < size_t > entry_point , Value initial_accumulator_value )
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 } } ;
2024-05-06 06:44:08 +02:00
TemporaryChange restore_saved_jump { m_scheduled_jump , Optional < size_t > { } } ;
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 ( ) ) ;
2024-05-01 19:33:49 +02:00
auto & running_execution_context = vm ( ) . running_execution_context ( ) ;
2024-05-12 18:49:03 +02:00
u32 registers_and_contants_count = executable . number_of_registers + executable . constants . size ( ) ;
if ( running_execution_context . registers_and_constants_and_locals . size ( ) < registers_and_contants_count )
running_execution_context . registers_and_constants_and_locals . resize ( registers_and_contants_count ) ;
2023-09-26 16:41:42 +02:00
2024-05-11 18:16:27 +02:00
TemporaryChange restore_running_execution_context { m_running_execution_context , & running_execution_context } ;
2024-05-05 22:06:55 +02:00
TemporaryChange restore_arguments { m_arguments , running_execution_context . arguments . span ( ) } ;
2024-05-12 18:49:03 +02:00
TemporaryChange restore_registers_and_constants_and_locals { m_registers_and_constants_and_locals , running_execution_context . registers_and_constants_and_locals . span ( ) } ;
2024-05-06 06:44:08 +02:00
reg ( Register : : accumulator ( ) ) = initial_accumulator_value ;
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-05-12 18:49:03 +02:00
for ( size_t i = 0 ; i < executable . constants . size ( ) ; + + i ) {
running_execution_context . registers_and_constants_and_locals [ executable . number_of_registers + i ] = executable . constants [ i ] ;
}
2024-05-06 06:44:08 +02:00
run_bytecode ( entry_point . value_or ( 0 ) ) ;
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 ) {
2024-05-12 18:49:03 +02:00
auto const & registers_and_constants_and_locals = running_execution_context . registers_and_constants_and_locals ;
for ( size_t i = 0 ; i < executable . number_of_registers ; + + i ) {
2023-02-12 21:54:02 -05:00
String value_string ;
2024-05-12 18:49:03 +02:00
if ( registers_and_constants_and_locals [ i ] . is_empty ( ) )
2023-08-07 11:12:38 +02:00
value_string = " (empty) " _string ;
2021-06-07 15:17:37 +02:00
else
2024-05-12 18:49:03 +02:00
value_string = registers_and_constants_and_locals [ 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 ( ) )
2024-05-12 18:49:03 +02:00
return { throw_completion ( exception ) , running_execution_context . registers_and_constants_and_locals [ 0 ] } ;
return { return_value , running_execution_context . registers_and_constants_and_locals [ 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-11 18:16:27 +02:00
running_execution_context ( ) . unwind_contexts . empend (
2023-05-13 18:53:14 +02:00
m_current_executable ,
2024-05-11 18:16:27 +02:00
running_execution_context ( ) . lexical_environment ) ;
running_execution_context ( ) . previously_scheduled_jumps . append ( m_scheduled_jump ) ;
2024-05-06 06:44:08 +02:00
m_scheduled_jump = { } ;
2021-06-10 15:04:38 +02:00
}
void Interpreter : : leave_unwind_context ( )
{
2024-05-11 18:16:27 +02:00
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-11 18:16:27 +02:00
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 ;
2024-05-11 18:16:27 +02:00
running_execution_context ( ) . lexical_environment = context . lexical_environment ;
2023-11-11 23:19:46 +01:00
}
2024-04-11 11:07:35 +02:00
void Interpreter : : restore_scheduled_jump ( )
{
2024-05-11 18:16:27 +02:00
m_scheduled_jump = 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-11 18:16:27 +02:00
m_scheduled_jump = 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-11 18:16:27 +02:00
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-05-05 22:06:55 +02:00
ThrowCompletionOr < NonnullGCPtr < Bytecode : : Executable > > compile ( VM & vm , ASTNode const & node , FunctionKind kind , DeprecatedFlyString const & name )
2023-06-22 15:59:18 +02:00
{
2024-05-05 22:06:55 +02:00
auto executable_result = Bytecode : : Generator : : generate_from_ast_node ( vm , node , kind ) ;
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 ;
if ( Bytecode : : g_dump_bytecode )
bytecode_executable - > dump ( ) ;
return bytecode_executable ;
}
ThrowCompletionOr < NonnullGCPtr < Bytecode : : Executable > > compile ( VM & vm , ECMAScriptFunctionObject const & function )
{
auto const & name = function . name ( ) ;
auto executable_result = Bytecode : : Generator : : generate_from_function ( vm , function ) ;
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-05-10 17:32:19 +02:00
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 ) ;
}
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 ( ) ) {
2024-05-18 10:58:11 +02:00
if ( ! Checked < i32 > : : subtraction_would_overflow ( lhs . as_i32 ( ) , rhs . as_i32 ( ) ) ) {
2024-02-20 11:59:46 +01:00
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 ) ;
2024-05-13 09:23:53 +02:00
if ( lhs . is_number ( ) & & rhs . is_number ( ) ) {
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) < rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , Value ( lhs . as_double ( ) < rhs . as_double ( ) ) ) ;
2024-02-20 11:59:46 +01:00
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 ) ;
2024-05-13 09:23:53 +02:00
if ( lhs . is_number ( ) & & rhs . is_number ( ) ) {
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) < = rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , Value ( lhs . as_double ( ) < = rhs . as_double ( ) ) ) ;
2024-02-20 11:59:46 +01:00
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 ) ;
2024-05-13 09:23:53 +02:00
if ( lhs . is_number ( ) & & rhs . is_number ( ) ) {
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) > rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , Value ( lhs . as_double ( ) > rhs . as_double ( ) ) ) ;
2024-02-20 11:59:46 +01:00
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 ) ;
2024-05-13 09:23:53 +02:00
if ( lhs . is_number ( ) & & rhs . is_number ( ) ) {
if ( lhs . is_int32 ( ) & & rhs . is_int32 ( ) ) {
interpreter . set ( m_dst , Value ( lhs . as_i32 ( ) > = rhs . as_i32 ( ) ) ) ;
return { } ;
}
interpreter . set ( m_dst , Value ( lhs . as_double ( ) > = rhs . as_double ( ) ) ) ;
2024-02-20 11:59:46 +01:00
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 )
2024-05-10 17:32:19 +02:00
void NewArray : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
auto array = MUST ( Array : : create ( interpreter . realm ( ) , 0 ) ) ;
for ( size_t i = 0 ; i < m_element_count ; i + + ) {
2024-05-08 12:43:08 +02:00
array - > indexed_properties ( ) . put ( i , interpreter . get ( m_elements [ i ] ) , default_attributes ) ;
2023-09-27 10:10:00 +02:00
}
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , array ) ;
2023-09-27 10:10:00 +02:00
}
2024-05-10 17:32:19 +02:00
void NewPrimitiveArray : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-11-17 22:07:23 +02:00
{
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
}
2024-05-11 22:54:41 +00:00
void AddPrivateName : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto const & name = interpreter . current_executable ( ) . get_identifier ( m_name ) ;
interpreter . vm ( ) . running_execution_context ( ) . private_environment - > add_private_name ( name ) ;
}
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 { } ;
}
2024-05-10 17:32:19 +02:00
void NewObject : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
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
}
2024-05-10 17:32:19 +02:00
void NewRegExp : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
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 ) ) ) ;
}
# define JS_DEFINE_NEW_BUILTIN_ERROR_OP(ErrorName) \
2024-05-10 17:32:19 +02:00
void New # # ErrorName : : execute_impl ( Bytecode : : Interpreter & interpreter ) const \
2024-02-04 08:00:54 +01:00
{ \
auto & vm = interpreter . vm ( ) ; \
auto & realm = * vm . current_realm ( ) ; \
interpreter . set ( dst ( ) , ErrorName : : create ( realm , interpreter . current_executable ( ) . get_string ( m_error_string ) ) ) ; \
} \
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 { } ;
}
2024-05-14 11:32:04 +02:00
ThrowCompletionOr < void > GetBinding : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
2024-05-11 17:22:59 +02:00
auto & vm = interpreter . vm ( ) ;
auto & executable = interpreter . current_executable ( ) ;
2024-05-11 18:28:03 +02:00
if ( m_cache . is_valid ( ) ) {
2024-05-11 18:16:27 +02:00
auto const * environment = interpreter . running_execution_context ( ) . lexical_environment . ptr ( ) ;
2024-05-11 18:28:03 +02:00
for ( size_t i = 0 ; i < m_cache . hops ; + + i )
2024-05-11 17:22:59 +02:00
environment = environment - > outer_environment ( ) ;
if ( ! environment - > is_permanently_screwed_by_eval ( ) ) {
2024-05-11 18:28:03 +02:00
interpreter . set ( dst ( ) , TRY ( static_cast < DeclarativeEnvironment const & > ( * environment ) . get_binding_value_direct ( vm , m_cache . index ) ) ) ;
2024-05-11 17:22:59 +02:00
return { } ;
}
2024-05-11 18:28:03 +02:00
m_cache = { } ;
2024-05-11 17:22:59 +02:00
}
auto reference = TRY ( vm . resolve_binding ( executable . get_identifier ( m_identifier ) ) ) ;
if ( reference . environment_coordinate ( ) . has_value ( ) )
2024-05-11 18:28:03 +02:00
m_cache = reference . environment_coordinate ( ) . value ( ) ;
2024-05-11 17:22:59 +02:00
interpreter . set ( dst ( ) , TRY ( reference . get_value ( vm ) ) ) ;
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 ) ,
2024-05-11 18:28:03 +02:00
m_cache ) ) ;
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-05-11 19:32:33 +02:00
interpreter . set ( dst ( ) , TRY ( get_global ( interpreter , 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 { } ;
}
2024-05-10 17:32:19 +02:00
void CreateLexicalEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
auto make_and_swap_envs = [ & ] ( auto & old_environment ) {
2024-05-09 17:10:20 +02:00
auto declarative_environment = new_declarative_environment ( * old_environment ) . ptr ( ) ;
declarative_environment - > ensure_capacity ( m_capacity ) ;
GCPtr < Environment > environment = declarative_environment ;
2023-09-27 10:10:00 +02:00
swap ( old_environment , environment ) ;
return environment ;
} ;
2024-05-11 18:16:27 +02:00
auto & running_execution_context = interpreter . running_execution_context ( ) ;
2024-05-01 19:33:49 +02:00
running_execution_context . saved_lexical_environments . append ( make_and_swap_envs ( running_execution_context . lexical_environment ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-05-11 22:54:41 +00:00
void CreatePrivateEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & running_execution_context = interpreter . vm ( ) . running_execution_context ( ) ;
auto outer_private_environment = running_execution_context . private_environment ;
running_execution_context . private_environment = new_private_environment ( interpreter . vm ( ) , outer_private_environment ) ;
}
2024-05-12 10:47:52 +02:00
void CreateVariableEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2024-05-05 22:06:55 +02:00
{
2024-05-11 18:16:27 +02:00
auto & running_execution_context = interpreter . running_execution_context ( ) ;
2024-05-05 22:06:55 +02:00
auto var_environment = new_declarative_environment ( * running_execution_context . lexical_environment ) ;
2024-05-09 17:10:20 +02:00
var_environment - > ensure_capacity ( m_capacity ) ;
2024-05-05 22:06:55 +02:00
running_execution_context . variable_environment = var_environment ;
running_execution_context . lexical_environment = var_environment ;
}
2023-09-27 10:10:00 +02:00
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 { } ;
}
2024-05-10 17:32:19 +02:00
void Catch : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-11-11 23:19:46 +01:00
{
2024-02-04 08:00:54 +01:00
interpreter . catch_exception ( dst ( ) ) ;
2023-11-11 23:19:46 +01:00
}
2024-05-10 17:32:19 +02:00
void LeaveFinally : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2024-04-11 11:58:18 +02:00
{
interpreter . leave_finally ( ) ;
}
2024-05-10 17:32:19 +02:00
void RestoreScheduledJump : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2024-04-11 11:07:35 +02:00
{
interpreter . restore_scheduled_jump ( ) ;
}
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
}
2024-05-05 22:06:55 +02:00
ThrowCompletionOr < void > CreateRestParams : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-05-11 18:16:27 +02:00
auto const & arguments = interpreter . running_execution_context ( ) . arguments ;
auto arguments_count = interpreter . running_execution_context ( ) . passed_argument_count ;
2024-05-05 22:06:55 +02:00
auto array = MUST ( Array : : create ( interpreter . realm ( ) , 0 ) ) ;
for ( size_t rest_index = m_rest_index ; rest_index < arguments_count ; + + rest_index )
array - > indexed_properties ( ) . append ( arguments [ rest_index ] ) ;
interpreter . set ( m_dst , array ) ;
return { } ;
}
ThrowCompletionOr < void > CreateArguments : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
2024-05-11 18:16:27 +02:00
auto const & function = interpreter . running_execution_context ( ) . function ;
auto const & arguments = interpreter . running_execution_context ( ) . arguments ;
auto const & environment = interpreter . running_execution_context ( ) . lexical_environment ;
2024-05-05 22:06:55 +02:00
2024-05-11 18:16:27 +02:00
auto passed_arguments = ReadonlySpan < Value > { arguments . data ( ) , interpreter . running_execution_context ( ) . passed_argument_count } ;
2024-05-05 22:06:55 +02:00
Object * arguments_object ;
if ( m_kind = = Kind : : Mapped ) {
arguments_object = create_mapped_arguments_object ( interpreter . vm ( ) , * function , function - > formal_parameters ( ) , passed_arguments , * environment ) ;
} else {
arguments_object = create_unmapped_arguments_object ( interpreter . vm ( ) , passed_arguments ) ;
}
2024-05-21 09:32:51 +01:00
if ( m_dst . has_value ( ) ) {
interpreter . set ( * m_dst , arguments_object ) ;
return { } ;
}
2024-05-05 22:06:55 +02:00
if ( m_is_immutable ) {
MUST ( environment - > create_immutable_binding ( interpreter . vm ( ) , interpreter . vm ( ) . names . arguments . as_string ( ) , false ) ) ;
} else {
MUST ( environment - > create_mutable_binding ( interpreter . vm ( ) , interpreter . vm ( ) . names . arguments . as_string ( ) , false ) ) ;
}
MUST ( environment - > initialize_binding ( interpreter . vm ( ) , interpreter . vm ( ) . names . arguments . as_string ( ) , arguments_object , Environment : : InitializeBindingHint : : Normal ) ) ;
return { } ;
}
2024-05-14 11:30:30 +02:00
template < EnvironmentMode environment_mode , BindingInitializationMode initialization_mode >
static ThrowCompletionOr < void > initialize_or_set_binding ( Interpreter & interpreter , IdentifierTableIndex identifier_index , Value value , EnvironmentCoordinate & cache )
2023-09-27 10:10:00 +02:00
{
auto & vm = interpreter . vm ( ) ;
2024-05-13 22:03:52 +02:00
2024-05-14 11:30:30 +02:00
auto * environment = environment_mode = = EnvironmentMode : : Lexical
? interpreter . running_execution_context ( ) . lexical_environment . ptr ( )
: interpreter . running_execution_context ( ) . variable_environment . ptr ( ) ;
if ( cache . is_valid ( ) ) {
for ( size_t i = 0 ; i < cache . hops ; + + i )
2024-05-13 22:03:52 +02:00
environment = environment - > outer_environment ( ) ;
if ( ! environment - > is_permanently_screwed_by_eval ( ) ) {
2024-05-14 11:30:30 +02:00
if constexpr ( initialization_mode = = BindingInitializationMode : : Initialize ) {
TRY ( static_cast < DeclarativeEnvironment & > ( * environment ) . initialize_binding_direct ( vm , cache . index , value , Environment : : InitializeBindingHint : : Normal ) ) ;
} else {
TRY ( static_cast < DeclarativeEnvironment & > ( * environment ) . set_mutable_binding_direct ( vm , cache . index , value , vm . in_strict_mode ( ) ) ) ;
2024-05-13 22:03:52 +02:00
}
return { } ;
}
2024-05-14 11:30:30 +02:00
cache = { } ;
2024-05-13 22:03:52 +02:00
}
2024-05-14 11:30:30 +02:00
auto reference = TRY ( vm . resolve_binding ( interpreter . current_executable ( ) . get_identifier ( identifier_index ) , environment ) ) ;
if ( reference . environment_coordinate ( ) . has_value ( ) )
cache = reference . environment_coordinate ( ) . value ( ) ;
if constexpr ( initialization_mode = = BindingInitializationMode : : Initialize ) {
TRY ( reference . initialize_referenced_binding ( vm , value ) ) ;
} else if ( initialization_mode = = BindingInitializationMode : : Set ) {
TRY ( reference . put_value ( vm , value ) ) ;
}
2023-09-27 10:10:00 +02:00
return { } ;
}
2024-05-14 11:30:30 +02:00
ThrowCompletionOr < void > InitializeLexicalBinding : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
return initialize_or_set_binding < EnvironmentMode : : Lexical , BindingInitializationMode : : Initialize > ( interpreter , m_identifier , interpreter . get ( m_src ) , m_cache ) ;
}
ThrowCompletionOr < void > InitializeVariableBinding : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
return initialize_or_set_binding < EnvironmentMode : : Var , BindingInitializationMode : : Initialize > ( interpreter , m_identifier , interpreter . get ( m_src ) , m_cache ) ;
}
ThrowCompletionOr < void > SetLexicalBinding : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
return initialize_or_set_binding < EnvironmentMode : : Lexical , BindingInitializationMode : : Set > ( interpreter , m_identifier , interpreter . get ( m_src ) , m_cache ) ;
}
ThrowCompletionOr < void > SetVariableBinding : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
return initialize_or_set_binding < EnvironmentMode : : Var , BindingInitializationMode : : Set > ( interpreter , m_identifier , interpreter . get ( m_src ) , m_cache ) ;
}
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
}
2024-05-20 11:53:28 +02:00
ThrowCompletionOr < void > GetLength : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto base_identifier = interpreter . current_executable ( ) . get_identifier ( m_base_identifier ) ;
auto base_value = interpreter . get ( base ( ) ) ;
auto & cache = interpreter . current_executable ( ) . property_lookup_caches [ m_cache_index ] ;
interpreter . set ( dst ( ) , TRY ( get_by_id < GetByIdMode : : Length > ( interpreter . vm ( ) , base_identifier , interpreter . vm ( ) . names . length . as_string ( ) , base_value , base_value , cache ) ) ) ;
return { } ;
}
ThrowCompletionOr < void > GetLengthWithThis : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto base_value = interpreter . get ( m_base ) ;
auto this_value = interpreter . get ( m_this_value ) ;
auto & cache = interpreter . current_executable ( ) . property_lookup_caches [ m_cache_index ] ;
interpreter . set ( dst ( ) , TRY ( get_by_id < GetByIdMode : : Length > ( interpreter . vm ( ) , { } , interpreter . vm ( ) . names . length . as_string ( ) , base_value , this_value , cache ) ) ) ;
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 ) ;
2024-05-11 18:16:27 +02:00
auto private_environment = interpreter . running_execution_context ( ) . private_environment ;
2023-09-27 10:10:00 +02:00
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 > 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.
2024-05-21 16:51:21 +01:00
auto & running_execution_context = interpreter . running_execution_context ( ) ;
if ( auto function = running_execution_context . function ; function & & is < ECMAScriptFunctionObject > ( * function ) & & ! static_cast < ECMAScriptFunctionObject & > ( * function ) . allocates_function_environment ( ) ) {
cached_this_value = running_execution_context . this_value ;
} else {
auto & vm = interpreter . vm ( ) ;
cached_this_value = TRY ( vm . resolve_this_binding ( ) ) ;
}
2023-09-27 10:10:00 +02:00
}
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 { } ;
}
2024-05-10 17:32:19 +02:00
void GetNewTarget : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , interpreter . vm ( ) . get_new_target ( ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-05-10 17:32:19 +02:00
void GetImportMeta : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
interpreter . set ( dst ( ) , interpreter . vm ( ) . get_import_meta ( ) ) ;
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 { } ;
}
2024-05-10 17:32:19 +02:00
void NewFunction : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
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
}
2024-05-10 17:32:19 +02:00
void Return : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
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
}
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 { } ;
}
2024-05-10 17:32:19 +02:00
void LeaveLexicalEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
2024-05-11 18:16:27 +02:00
auto & running_execution_context = interpreter . running_execution_context ( ) ;
2024-05-01 19:33:49 +02:00
running_execution_context . lexical_environment = running_execution_context . saved_lexical_environments . take_last ( ) ;
2023-09-27 10:10:00 +02:00
}
2024-05-11 22:54:41 +00:00
void LeavePrivateEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & running_execution_context = interpreter . vm ( ) . running_execution_context ( ) ;
running_execution_context . private_environment = running_execution_context . private_environment - > outer_environment ( ) ;
}
2024-05-10 17:32:19 +02:00
void LeaveUnwindContext : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
interpreter . leave_unwind_context ( ) ;
}
2024-05-12 10:47:52 +02:00
void Yield : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
2024-02-04 08:00:54 +01:00
auto yielded_value = interpreter . get ( m_value ) . value_or ( js_undefined ( ) ) ;
2024-05-18 17:25:43 +02:00
interpreter . do_return (
interpreter . do_yield ( yielded_value , m_continuation_label ) ) ;
}
2024-02-04 08:00:54 +01:00
2024-05-18 17:25:43 +02:00
void PrepareYield : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto value = interpreter . get ( m_value ) . value_or ( js_undefined ( ) ) ;
interpreter . set ( m_dest , interpreter . do_yield ( value , { } ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-05-12 10:47:52 +02:00
void Await : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
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
2024-05-06 06:44:08 +02:00
object - > define_direct_property ( " continuation " , Value ( m_continuation_label . address ( ) ) , JS : : default_attributes ) ;
2023-09-27 10:10:00 +02:00
object - > define_direct_property ( " isAwait " , Value ( true ) , JS : : default_attributes ) ;
interpreter . do_return ( object ) ;
}
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!)
2024-05-10 09:28:48 +02:00
TRY ( iterator_close ( vm , iterator , Completion { m_completion_type , m_completion_value } ) ) ;
2023-09-27 10:10:00 +02:00
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!)
2024-05-10 09:28:48 +02:00
TRY ( async_iterator_close ( vm , iterator , Completion { m_completion_type , m_completion_value } ) ) ;
2023-09-27 10:10:00 +02:00
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 ( ) ) ;
2024-05-11 22:54:41 +00:00
Vector < Value > element_keys ;
for ( size_t i = 0 ; i < m_element_keys_count ; + + i ) {
Value element_key ;
if ( m_element_keys [ i ] . has_value ( ) )
element_key = interpreter . get ( m_element_keys [ i ] . value ( ) ) ;
element_keys . append ( element_key ) ;
}
interpreter . set ( dst ( ) , TRY ( new_class ( interpreter . vm ( ) , super_class , m_class_expression , m_lhs_name , element_keys ) ) ) ;
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 { } ;
}
2024-05-10 17:32:19 +02:00
void BlockDeclarationInstantiation : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2023-09-27 10:10:00 +02:00
{
auto & vm = interpreter . vm ( ) ;
2024-05-11 18:16:27 +02:00
auto old_environment = interpreter . running_execution_context ( ) . lexical_environment ;
auto & running_execution_context = interpreter . running_execution_context ( ) ;
2024-05-01 19:33:49 +02:00
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
}
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-05-08 12:43:08 +02:00
builder . appendff ( " , {} " , format_operand_list ( " args " sv , { m_elements , m_element_count } , 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-05-11 22:54:41 +00:00
ByteString AddPrivateName : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " AddPrivateName {} " sv , executable . identifier_table - > get ( m_name ) ) ;
}
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
}
2024-05-14 11:32:04 +02:00
ByteString GetBinding : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-05-14 11:32:04 +02:00
return ByteString : : formatted ( " GetBinding {}, {} " ,
2024-02-04 08:00:54 +01:00
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
{
2024-05-06 10:12:02 +02:00
return ByteString : : formatted ( " DeleteVariable {} " , 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 ;
}
2024-05-11 22:54:41 +00:00
ByteString CreatePrivateEnvironment : : to_byte_string_impl ( Bytecode : : Executable const & ) const
{
return " CreatePrivateEnvironment " sv ;
}
2024-05-05 22:06:55 +02:00
ByteString CreateVariableEnvironment : : to_byte_string_impl ( Bytecode : : Executable const & ) const
{
return " CreateVariableEnvironment " 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 " ;
2024-05-06 10:12:02 +02:00
return ByteString : : formatted ( " CreateVariable env:{} immutable:{} global:{} {} " , mode_string , m_is_immutable , m_is_global , executable . identifier_table - > get ( m_identifier ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-05-05 22:06:55 +02:00
ByteString CreateRestParams : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " CreateRestParams {}, rest_index:{} " , format_operand ( " dst " sv , m_dst , executable ) , m_rest_index ) ;
}
2024-05-21 09:32:51 +01:00
ByteString CreateArguments : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2024-05-05 22:06:55 +02:00
{
2024-05-21 09:32:51 +01:00
StringBuilder builder ;
builder . appendff ( " CreateArguments " ) ;
if ( m_dst . has_value ( ) )
builder . appendff ( " {} " , format_operand ( " dst " sv , * m_dst , executable ) ) ;
builder . appendff ( " {} immutable:{} " , m_kind = = Kind : : Mapped ? " mapped " sv : " unmapped " sv , m_is_immutable ) ;
return builder . to_byte_string ( ) ;
2024-05-05 22:06:55 +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
}
2024-05-14 11:30:30 +02:00
ByteString InitializeLexicalBinding : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
2023-09-27 10:10:00 +02:00
{
2024-05-14 11:30:30 +02:00
return ByteString : : formatted ( " InitializeLexicalBinding {}, {} " ,
2024-02-04 08:00:54 +01:00
executable . identifier_table - > get ( m_identifier ) ,
2024-05-14 11:30:30 +02:00
format_operand ( " src " sv , src ( ) , executable ) ) ;
}
ByteString InitializeVariableBinding : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " InitializeVariableBinding {}, {} " ,
executable . identifier_table - > get ( m_identifier ) ,
format_operand ( " src " sv , src ( ) , executable ) ) ;
}
ByteString SetLexicalBinding : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " SetLexicalBinding {}, {} " ,
executable . identifier_table - > get ( m_identifier ) ,
format_operand ( " src " sv , src ( ) , executable ) ) ;
}
ByteString SetVariableBinding : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " SetVariableBinding {}, {} " ,
executable . identifier_table - > get ( m_identifier ) ,
format_operand ( " src " sv , src ( ) , executable ) ) ;
2023-09-27 10:10:00 +02:00
}
2024-05-05 22:06:55 +02:00
ByteString GetArgument : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " GetArgument {}, {} " , index ( ) , format_operand ( " dst " sv , dst ( ) , executable ) ) ;
}
ByteString SetArgument : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " SetArgument {}, {} " , index ( ) , 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
}
2024-05-20 11:53:28 +02:00
ByteString GetLength : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " GetLength {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ) ;
}
ByteString GetLengthWithThis : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " GetLengthWithThis {}, {}, {} " ,
format_operand ( " dst " sv , m_dst , executable ) ,
format_operand ( " base " sv , m_base , executable ) ,
format_operand ( " this " sv , m_this_value , executable ) ) ;
}
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
{
2024-05-05 11:52:14 +02:00
return ByteString : : formatted ( " Jump {} " , m_target ) ;
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
{
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 ) ,
2024-05-05 11:52:14 +02:00
m_true_target ,
m_false_target ) ;
2023-09-27 10:10:00 +02:00
}
2024-05-06 10:15:17 +02:00
ByteString JumpTrue : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " JumpTrue {}, {} " ,
format_operand ( " condition " sv , m_condition , executable ) ,
m_target ) ;
}
ByteString JumpFalse : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " JumpFalse {}, {} " ,
format_operand ( " condition " sv , m_condition , executable ) ,
m_target ) ;
}
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
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " JumpNullish {}, null:{} nonnull:{} " ,
format_operand ( " condition " sv , m_condition , executable ) ,
2024-05-05 11:52:14 +02:00
m_true_target ,
m_false_target ) ;
2023-09-27 10:10:00 +02:00
}
2024-05-13 09:23:53 +02:00
# define HANDLE_COMPARISON_OP(op_TitleCase, op_snake_case, numeric_operator) \
2024-05-09 15:13:31 +02:00
ByteString Jump # # op_TitleCase : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const \
{ \
return ByteString : : formatted ( " Jump " # op_TitleCase " {}, {}, true:{}, false:{} " , \
format_operand ( " lhs " sv , m_lhs , executable ) , \
format_operand ( " rhs " sv , m_rhs , executable ) , \
m_true_target , \
m_false_target ) ; \
}
JS_ENUMERATE_COMPARISON_OPS ( HANDLE_COMPARISON_OP )
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
{
2024-02-04 08:00:54 +01:00
return ByteString : : formatted ( " JumpUndefined {}, undefined:{} defined:{} " ,
format_operand ( " condition " sv , m_condition , executable ) ,
2024-05-05 11:52:14 +02:00
m_true_target ,
m_false_target ) ;
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 ;
2024-05-08 12:43:08 +02:00
builder . appendff ( " Call{} {}, {}, {}, " sv ,
2024-02-20 15:59:45 +01:00
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-05-06 10:12:02 +02:00
builder . appendff ( " , lhs_name:{} " sv , executable . get_identifier ( 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 ;
}
2024-05-11 22:54:41 +00:00
ByteString LeavePrivateEnvironment : : to_byte_string_impl ( Bytecode : : Executable const & ) const
{
return " LeavePrivateEnvironment " 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 ( ) ) {
2024-05-06 06:44:08 +02:00
return ByteString : : formatted ( " Yield continuation:{}, {} " ,
m_continuation_label . value ( ) ,
2024-02-04 08:00:54 +01:00
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-05-18 17:25:43 +02:00
ByteString PrepareYield : : to_byte_string_impl ( Bytecode : : Executable const & executable ) const
{
return ByteString : : formatted ( " PrepareYield {}, {} " ,
format_operand ( " dst " sv , m_dest , executable ) ,
format_operand ( " value " sv , m_value , executable ) ) ;
}
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-05-06 06:44:08 +02:00
return ByteString : : formatted ( " Await {}, continuation:{} " ,
2024-02-04 08:00:54 +01:00
format_operand ( " argument " sv , m_argument , executable ) ,
2024-05-06 06:44:08 +02:00
m_continuation_label ) ;
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
}