2021-06-03 10:46:30 +02:00
/*
* Copyright ( c ) 2021 , Andreas Kling < kling @ serenityos . org >
2022-01-09 19:12:24 +01:00
* Copyright ( c ) 2021 - 2022 , Linus Groh < linusg @ serenityos . org >
2021-06-09 18:18:56 +02:00
* Copyright ( c ) 2021 , Gunnar Beutner < gbeutner @ serenityos . org >
2021-06-03 10:46:30 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2021-06-13 15:30:32 -07:00
# include <AK/HashTable.h>
2021-06-03 10:46:30 +02:00
# include <LibJS/Bytecode/Interpreter.h>
# include <LibJS/Bytecode/Op.h>
2021-10-23 01:49:10 +03:00
# include <LibJS/Runtime/AbstractOperations.h>
2021-06-08 23:06:52 +02:00
# include <LibJS/Runtime/Array.h>
2021-06-08 07:59:25 +02:00
# include <LibJS/Runtime/BigInt.h>
2021-07-01 12:24:46 +02:00
# include <LibJS/Runtime/DeclarativeEnvironment.h>
2021-09-24 22:40:38 +02:00
# include <LibJS/Runtime/ECMAScriptFunctionObject.h>
2021-07-01 12:24:46 +02:00
# include <LibJS/Runtime/Environment.h>
2021-06-03 18:26:32 +02:00
# include <LibJS/Runtime/GlobalObject.h>
2022-01-09 19:12:24 +01:00
# include <LibJS/Runtime/Iterator.h>
2021-06-13 13:40:48 -07:00
# include <LibJS/Runtime/IteratorOperations.h>
2022-03-18 20:18:19 +03:30
# include <LibJS/Runtime/NativeFunction.h>
2022-03-13 16:01:18 +03:30
# include <LibJS/Runtime/ObjectEnvironment.h>
2021-06-19 17:17:40 -07:00
# include <LibJS/Runtime/RegExpObject.h>
2021-06-03 10:46:30 +02:00
# include <LibJS/Runtime/Value.h>
2021-06-07 15:12:43 +02:00
namespace JS : : Bytecode {
2021-06-09 10:02:01 +02:00
String Instruction : : to_string ( Bytecode : : Executable const & executable ) const
2021-06-07 15:12:43 +02:00
{
# define __BYTECODE_OP(op) \
case Instruction : : Type : : op : \
2021-06-15 18:08:12 +04:30
return static_cast < Bytecode : : Op : : op const & > ( * this ) . to_string_impl ( executable ) ;
2021-06-07 15:12:43 +02:00
switch ( type ( ) ) {
ENUMERATE_BYTECODE_OPS ( __BYTECODE_OP )
default :
VERIFY_NOT_REACHED ( ) ;
}
# undef __BYTECODE_OP
}
}
2021-06-03 10:46:30 +02:00
namespace JS : : Bytecode : : Op {
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > Load : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-03 10:46:30 +02:00
{
2021-06-07 20:58:36 -07:00
interpreter . accumulator ( ) = interpreter . reg ( m_src ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-03 10:46:30 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > LoadImmediate : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-07 22:05:09 +02:00
{
2021-06-07 20:58:36 -07:00
interpreter . accumulator ( ) = m_value ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-07 20:58:36 -07:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > Store : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-07 20:58:36 -07:00
{
interpreter . reg ( m_dst ) = interpreter . accumulator ( ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-07 22:05:09 +02:00
}
2021-10-19 00:13:29 +03:00
static ThrowCompletionOr < Value > abstract_inequals ( GlobalObject & global_object , Value src1 , Value src2 )
2021-06-03 10:46:30 +02:00
{
2021-10-19 00:13:29 +03:00
return Value ( ! TRY ( is_loosely_equal ( global_object , src1 , src2 ) ) ) ;
2021-06-03 10:46:30 +02:00
}
2021-10-19 00:13:29 +03:00
static ThrowCompletionOr < Value > abstract_equals ( GlobalObject & global_object , Value src1 , Value src2 )
2021-06-03 18:32:33 +02:00
{
2021-10-19 00:13:29 +03:00
return Value ( TRY ( is_loosely_equal ( global_object , src1 , src2 ) ) ) ;
2021-06-03 18:32:33 +02:00
}
2021-10-19 00:13:29 +03:00
static ThrowCompletionOr < Value > typed_inequals ( GlobalObject & , Value src1 , Value src2 )
2021-06-07 19:17:20 +02:00
{
2021-09-23 23:43:28 +02:00
return Value ( ! is_strictly_equal ( src1 , src2 ) ) ;
2021-06-07 19:17:20 +02:00
}
2021-10-19 00:13:29 +03:00
static ThrowCompletionOr < Value > typed_equals ( GlobalObject & , Value src1 , Value src2 )
2021-06-07 19:17:20 +02:00
{
2021-09-23 23:43:28 +02:00
return Value ( is_strictly_equal ( src1 , src2 ) ) ;
2021-06-07 19:17:20 +02:00
}
2022-02-07 14:36:45 +01:00
# define JS_DEFINE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
ThrowCompletionOr < void > OpTitleCase : : execute_impl ( Bytecode : : Interpreter & interpreter ) const \
{ \
auto lhs = interpreter . reg ( m_lhs_reg ) ; \
auto rhs = interpreter . accumulator ( ) ; \
interpreter . accumulator ( ) = TRY ( op_snake_case ( interpreter . global_object ( ) , lhs , rhs ) ) ; \
return { } ; \
} \
String OpTitleCase : : to_string_impl ( Bytecode : : Executable const & ) const \
{ \
return String : : formatted ( # OpTitleCase " {} " , m_lhs_reg ) ; \
2021-06-07 23:08:35 +02:00
}
2021-06-07 21:13:37 +01:00
2021-06-07 23:08:35 +02:00
JS_ENUMERATE_COMMON_BINARY_OPS ( JS_DEFINE_COMMON_BINARY_OP )
2021-06-07 21:18:19 +01:00
2021-10-19 00:13:29 +03:00
static ThrowCompletionOr < Value > not_ ( GlobalObject & , Value value )
2021-06-07 21:13:37 +01:00
{
2021-06-07 23:08:35 +02:00
return Value ( ! value . to_boolean ( ) ) ;
2021-06-07 21:13:37 +01:00
}
2021-10-19 00:13:29 +03:00
static ThrowCompletionOr < Value > typeof_ ( GlobalObject & global_object , Value value )
2021-06-07 19:53:47 +01:00
{
2021-10-19 00:13:29 +03:00
return Value ( js_string ( global_object . vm ( ) , value . typeof ( ) ) ) ;
2021-06-07 19:53:47 +01:00
}
2022-02-07 14:36:45 +01:00
# define JS_DEFINE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \
ThrowCompletionOr < void > OpTitleCase : : execute_impl ( Bytecode : : Interpreter & interpreter ) const \
{ \
interpreter . accumulator ( ) = TRY ( op_snake_case ( interpreter . global_object ( ) , interpreter . accumulator ( ) ) ) ; \
return { } ; \
} \
String OpTitleCase : : to_string_impl ( Bytecode : : Executable const & ) const \
{ \
return # OpTitleCase ; \
2021-06-07 23:08:35 +02:00
}
2021-06-07 19:53:47 +01:00
2021-06-07 23:08:35 +02:00
JS_ENUMERATE_COMMON_UNARY_OPS ( JS_DEFINE_COMMON_UNARY_OP )
2021-06-07 19:53:47 +01:00
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > NewBigInt : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-08 07:59:25 +02:00
{
2021-06-07 20:58:36 -07:00
interpreter . accumulator ( ) = js_bigint ( interpreter . vm ( ) . heap ( ) , m_bigint ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-08 07:59:25 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > NewArray : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-08 23:06:52 +02:00
{
2022-03-14 12:44:01 +00:00
auto * array = MUST ( Array : : create ( interpreter . global_object ( ) , 0 ) ) ;
for ( size_t i = 0 ; i < m_element_count ; i + + ) {
2022-03-14 14:48:42 +00:00
auto & value = interpreter . reg ( Register ( m_elements [ 0 ] . index ( ) + i ) ) ;
2022-03-14 12:44:01 +00:00
array - > indexed_properties ( ) . put ( i , value , default_attributes ) ;
}
interpreter . accumulator ( ) = array ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-08 23:06:52 +02:00
}
2022-01-09 19:12:24 +01:00
// FIXME: Since the accumulator is a Value, we store an object there and have to convert back and forth between that an Iterator records. Not great.
// Make sure to put this into the accumulator before the iterator object disappears from the stack to prevent the members from being GC'd.
static Object * iterator_to_object ( GlobalObject & global_object , Iterator iterator )
{
auto & vm = global_object . vm ( ) ;
auto * object = Object : : create ( global_object , nullptr ) ;
object - > define_direct_property ( vm . names . iterator , iterator . iterator , 0 ) ;
object - > define_direct_property ( vm . names . next , iterator . next_method , 0 ) ;
object - > define_direct_property ( vm . names . done , Value ( iterator . done ) , 0 ) ;
return object ;
}
static Iterator object_to_iterator ( GlobalObject & global_object , Object & object )
{
auto & vm = global_object . vm ( ) ;
return Iterator {
. iterator = & MUST ( object . get ( vm . names . iterator ) ) . as_object ( ) ,
. next_method = MUST ( object . get ( vm . names . next ) ) ,
. done = MUST ( object . get ( vm . names . done ) ) . as_bool ( )
} ;
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > IteratorToArray : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-13 14:06:26 -07:00
{
auto & global_object = interpreter . global_object ( ) ;
2022-02-07 14:36:45 +01:00
auto iterator_object = TRY ( interpreter . accumulator ( ) . to_object ( global_object ) ) ;
auto iterator = object_to_iterator ( global_object , * iterator_object ) ;
2021-06-13 14:06:26 -07:00
2021-10-22 01:34:06 +03:00
auto * array = MUST ( Array : : create ( global_object , 0 ) ) ;
2021-06-13 14:06:26 -07:00
size_t index = 0 ;
while ( true ) {
2022-02-07 14:36:45 +01:00
auto * iterator_result = TRY ( iterator_next ( global_object , iterator ) ) ;
2021-06-13 14:06:26 -07:00
2022-02-07 14:36:45 +01:00
auto complete = TRY ( iterator_complete ( global_object , * iterator_result ) ) ;
2021-06-13 14:06:26 -07:00
if ( complete ) {
interpreter . accumulator ( ) = array ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-13 14:06:26 -07:00
}
2022-02-07 14:36:45 +01:00
auto value = TRY ( iterator_value ( global_object , * iterator_result ) ) ;
2021-06-13 14:06:26 -07:00
2021-10-03 01:18:46 +01:00
MUST ( array - > create_data_property_or_throw ( index , value ) ) ;
2021-06-13 14:06:26 -07:00
index + + ;
}
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-13 14:06:26 -07:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > NewString : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-03 18:26:32 +02:00
{
2021-06-09 10:02:01 +02:00
interpreter . accumulator ( ) = js_string ( interpreter . vm ( ) , interpreter . current_executable ( ) . get_string ( m_string ) ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-03 18:26:32 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > NewObject : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-04 20:30:23 +02:00
{
2021-06-16 20:52:30 +01:00
interpreter . accumulator ( ) = Object : : create ( interpreter . global_object ( ) , interpreter . global_object ( ) . object_prototype ( ) ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-07 20:58:36 -07:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > NewRegExp : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-19 17:17:40 -07:00
{
auto source = interpreter . current_executable ( ) . get_string ( m_source_index ) ;
auto flags = interpreter . current_executable ( ) . get_string ( m_flags_index ) ;
2022-02-07 14:36:45 +01:00
interpreter . accumulator ( ) = TRY ( regexp_create ( interpreter . global_object ( ) , js_string ( interpreter . vm ( ) , source ) , js_string ( interpreter . vm ( ) , flags ) ) ) ;
return { } ;
2021-06-19 17:17:40 -07:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > CopyObjectExcludingProperties : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-13 15:30:32 -07:00
{
2022-02-07 14:36:45 +01:00
auto * from_object = TRY ( interpreter . reg ( m_from_object ) . to_object ( interpreter . global_object ( ) ) ) ;
2021-06-13 15:30:32 -07:00
auto * to_object = Object : : create ( interpreter . global_object ( ) , interpreter . global_object ( ) . object_prototype ( ) ) ;
HashTable < Value , ValueTraits > excluded_names ;
2022-02-07 14:36:45 +01:00
for ( size_t i = 0 ; i < m_excluded_names_count ; + + i )
2021-06-13 15:30:32 -07:00
excluded_names . set ( interpreter . reg ( m_excluded_names [ i ] ) ) ;
2022-02-07 14:36:45 +01:00
auto own_keys = TRY ( from_object - > internal_own_property_keys ( ) ) ;
2021-06-13 15:30:32 -07:00
for ( auto & key : own_keys ) {
if ( ! excluded_names . contains ( key ) ) {
2022-02-07 14:36:45 +01:00
auto property_key = TRY ( key . to_property_key ( interpreter . global_object ( ) ) ) ;
auto property_value = TRY ( from_object - > get ( property_key ) ) ;
2022-02-06 15:59:04 +00:00
to_object - > define_direct_property ( property_key , property_value , JS : : default_attributes ) ;
2021-06-13 15:30:32 -07:00
}
}
interpreter . accumulator ( ) = to_object ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-13 15:30:32 -07:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > ConcatString : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-07 20:58:36 -07:00
{
2022-02-07 14:36:45 +01:00
interpreter . reg ( m_lhs ) = TRY ( add ( interpreter . global_object ( ) , interpreter . reg ( m_lhs ) , interpreter . accumulator ( ) ) ) ;
return { } ;
2021-06-04 20:30:23 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > GetVariable : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-03 18:26:32 +02:00
{
2022-02-07 14:36:45 +01:00
auto get_reference = [ & ] ( ) - > ThrowCompletionOr < Reference > {
2021-10-24 15:36:24 +02:00
auto const & string = interpreter . current_executable ( ) . get_identifier ( m_identifier ) ;
if ( m_cached_environment_coordinate . has_value ( ) ) {
auto * environment = interpreter . vm ( ) . running_execution_context ( ) . lexical_environment ;
for ( size_t i = 0 ; i < m_cached_environment_coordinate - > hops ; + + i )
environment = environment - > outer_environment ( ) ;
VERIFY ( environment ) ;
VERIFY ( environment - > is_declarative_environment ( ) ) ;
if ( ! environment - > is_permanently_screwed_by_eval ( ) ) {
return Reference { * environment , string , interpreter . vm ( ) . in_strict_mode ( ) , m_cached_environment_coordinate } ;
}
m_cached_environment_coordinate = { } ;
}
2022-02-07 14:36:45 +01:00
auto reference = TRY ( interpreter . vm ( ) . resolve_binding ( string ) ) ;
2021-10-24 15:36:24 +02:00
if ( reference . environment_coordinate ( ) . has_value ( ) )
m_cached_environment_coordinate = reference . environment_coordinate ( ) ;
return reference ;
2022-02-07 14:36:45 +01:00
} ;
auto reference = TRY ( get_reference ( ) ) ;
interpreter . accumulator ( ) = TRY ( reference . get_value ( interpreter . global_object ( ) ) ) ;
return { } ;
2021-06-03 18:26:32 +02:00
}
2022-02-12 19:48:45 +03:30
ThrowCompletionOr < void > CreateEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto make_and_swap_envs = [ & ] ( auto * & old_environment ) {
Environment * environment = new_declarative_environment ( * old_environment ) ;
swap ( old_environment , environment ) ;
return environment ;
} ;
if ( m_mode = = EnvironmentMode : : Lexical )
interpreter . saved_lexical_environment_stack ( ) . append ( make_and_swap_envs ( interpreter . vm ( ) . running_execution_context ( ) . lexical_environment ) ) ;
else if ( m_mode = = EnvironmentMode : : Var )
interpreter . saved_variable_environment_stack ( ) . append ( make_and_swap_envs ( interpreter . vm ( ) . running_execution_context ( ) . variable_environment ) ) ;
return { } ;
}
2022-03-13 16:01:18 +03:30
ThrowCompletionOr < void > EnterObjectEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & old_environment = interpreter . vm ( ) . running_execution_context ( ) . lexical_environment ;
interpreter . saved_lexical_environment_stack ( ) . append ( old_environment ) ;
auto object = TRY ( interpreter . accumulator ( ) . to_object ( interpreter . global_object ( ) ) ) ;
interpreter . vm ( ) . running_execution_context ( ) . lexical_environment = new_object_environment ( * object , true , old_environment ) ;
return { } ;
}
2022-02-12 19:48:45 +03:30
ThrowCompletionOr < void > CreateVariable : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-03 18:26:32 +02:00
{
2021-09-22 12:44:56 +02:00
auto & vm = interpreter . vm ( ) ;
2022-02-12 19:48:45 +03:30
auto const & name = interpreter . current_executable ( ) . get_identifier ( m_identifier ) ;
2021-09-22 12:44:56 +02:00
2022-02-12 19:48:45 +03:30
if ( m_mode = = EnvironmentMode : : Lexical ) {
// Note: This is papering over an issue where "FunctionDeclarationInstantiation" creates these bindings for us.
// Instead of crashing in there, we'll just raise an exception here.
if ( TRY ( vm . lexical_environment ( ) - > has_binding ( name ) ) )
return vm . throw_completion < InternalError > ( interpreter . global_object ( ) , String : : formatted ( " Lexical environment already has binding '{}' " , name ) ) ;
if ( m_is_immutable )
vm . lexical_environment ( ) - > create_immutable_binding ( interpreter . global_object ( ) , name , vm . in_strict_mode ( ) ) ;
else
vm . lexical_environment ( ) - > create_mutable_binding ( interpreter . global_object ( ) , name , vm . in_strict_mode ( ) ) ;
} else {
if ( m_is_immutable )
vm . variable_environment ( ) - > create_immutable_binding ( interpreter . global_object ( ) , name , vm . in_strict_mode ( ) ) ;
else
vm . variable_environment ( ) - > create_mutable_binding ( interpreter . global_object ( ) , name , vm . in_strict_mode ( ) ) ;
}
return { } ;
}
ThrowCompletionOr < void > SetVariable : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
auto & vm = interpreter . vm ( ) ;
auto const & name = interpreter . current_executable ( ) . get_identifier ( m_identifier ) ;
auto environment = m_mode = = EnvironmentMode : : Lexical ? vm . running_execution_context ( ) . lexical_environment : vm . running_execution_context ( ) . variable_environment ;
auto reference = TRY ( vm . resolve_binding ( name , environment ) ) ;
switch ( m_initialization_mode ) {
case InitializationMode : : Initialize :
TRY ( reference . initialize_referenced_binding ( interpreter . global_object ( ) , interpreter . accumulator ( ) ) ) ;
break ;
case InitializationMode : : Set :
TRY ( reference . put_value ( interpreter . global_object ( ) , interpreter . accumulator ( ) ) ) ;
break ;
case InitializationMode : : InitializeOrSet :
VERIFY ( reference . is_environment_reference ( ) ) ;
VERIFY ( reference . base_environment ( ) . is_declarative_environment ( ) ) ;
TRY ( static_cast < DeclarativeEnvironment & > ( reference . base_environment ( ) ) . initialize_or_set_mutable_binding ( interpreter . global_object ( ) , name , interpreter . accumulator ( ) ) ) ;
break ;
}
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-03 18:26:32 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > GetById : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-04 21:03:53 +02:00
{
2022-02-07 14:36:45 +01:00
auto * object = TRY ( interpreter . accumulator ( ) . to_object ( interpreter . global_object ( ) ) ) ;
interpreter . accumulator ( ) = TRY ( object - > get ( interpreter . current_executable ( ) . get_identifier ( m_property ) ) ) ;
return { } ;
2021-06-04 21:03:53 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > PutById : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-04 20:47:07 +02:00
{
2022-02-07 14:36:45 +01:00
auto * object = TRY ( interpreter . reg ( m_base ) . to_object ( interpreter . global_object ( ) ) ) ;
TRY ( object - > set ( interpreter . current_executable ( ) . get_identifier ( m_property ) , interpreter . accumulator ( ) , Object : : ShouldThrowExceptions : : Yes ) ) ;
return { } ;
2021-06-04 20:47:07 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > Jump : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-04 12:07:38 +02:00
{
2021-06-09 06:49:58 +04:30
interpreter . jump ( * m_true_target ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-04 12:07:38 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > ResolveThisBinding : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-10-24 14:43:00 +02:00
{
2022-02-07 14:36:45 +01:00
interpreter . accumulator ( ) = TRY ( interpreter . vm ( ) . resolve_this_binding ( interpreter . global_object ( ) ) ) ;
return { } ;
2021-10-24 14:43:00 +02:00
}
2022-03-19 19:40:21 +00:00
ThrowCompletionOr < void > GetNewTarget : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
interpreter . accumulator ( ) = interpreter . vm ( ) . get_new_target ( ) ;
return { } ;
}
2021-06-13 20:40:20 +04:30
void Jump : : replace_references_impl ( BasicBlock const & from , BasicBlock const & to )
{
if ( m_true_target . has_value ( ) & & & m_true_target - > block ( ) = = & from )
m_true_target = Label { to } ;
if ( m_false_target . has_value ( ) & & & m_false_target - > block ( ) = = & from )
m_false_target = Label { to } ;
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > JumpConditional : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-04 12:07:38 +02:00
{
2021-06-09 06:49:58 +04:30
VERIFY ( m_true_target . has_value ( ) ) ;
VERIFY ( m_false_target . has_value ( ) ) ;
2021-06-07 20:58:36 -07:00
auto result = interpreter . accumulator ( ) ;
2021-06-07 22:53:33 +02:00
if ( result . to_boolean ( ) )
2021-06-09 06:49:58 +04:30
interpreter . jump ( m_true_target . value ( ) ) ;
else
interpreter . jump ( m_false_target . value ( ) ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-04 12:20:44 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > JumpNullish : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-08 02:18:47 +02:00
{
2021-06-09 06:49:58 +04:30
VERIFY ( m_true_target . has_value ( ) ) ;
VERIFY ( m_false_target . has_value ( ) ) ;
2021-06-07 20:58:36 -07:00
auto result = interpreter . accumulator ( ) ;
2021-06-09 06:49:58 +04:30
if ( result . is_nullish ( ) )
interpreter . jump ( m_true_target . value ( ) ) ;
else
interpreter . jump ( m_false_target . value ( ) ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-08 02:18:47 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > JumpUndefined : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-13 12:24:40 -07:00
{
VERIFY ( m_true_target . has_value ( ) ) ;
VERIFY ( m_false_target . has_value ( ) ) ;
auto result = interpreter . accumulator ( ) ;
if ( result . is_undefined ( ) )
interpreter . jump ( m_true_target . value ( ) ) ;
else
interpreter . jump ( m_false_target . value ( ) ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-13 12:24:40 -07:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > Call : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-05 15:15:30 +02:00
{
auto callee = interpreter . reg ( m_callee ) ;
2022-03-19 19:41:15 +00:00
if ( m_type = = CallType : : Call & & ! callee . is_function ( ) )
2022-02-07 14:36:45 +01:00
return interpreter . vm ( ) . throw_completion < TypeError > ( interpreter . global_object ( ) , ErrorType : : IsNotA , callee . to_string_without_side_effects ( ) , " function " sv ) ;
2022-03-19 19:41:15 +00:00
if ( m_type = = CallType : : Construct & & ! callee . is_constructor ( ) )
return interpreter . vm ( ) . throw_completion < TypeError > ( interpreter . global_object ( ) , ErrorType : : IsNotA , callee . to_string_without_side_effects ( ) , " constructor " sv ) ;
2021-06-05 15:15:30 +02:00
auto & function = callee . as_function ( ) ;
auto this_value = interpreter . reg ( m_this_value ) ;
2022-03-13 11:48:50 +03:30
MarkedVector < Value > argument_values { interpreter . vm ( ) . heap ( ) } ;
for ( size_t i = 0 ; i < m_argument_count ; + + i )
argument_values . append ( interpreter . reg ( m_arguments [ i ] ) ) ;
2022-02-07 14:36:45 +01:00
2022-03-13 11:48:50 +03:30
Value return_value ;
if ( m_type = = CallType : : Call )
return_value = TRY ( call ( interpreter . global_object ( ) , function , this_value , move ( argument_values ) ) ) ;
else
return_value = TRY ( construct ( interpreter . global_object ( ) , function , move ( argument_values ) ) ) ;
2021-06-05 15:15:30 +02:00
2021-06-07 20:58:36 -07:00
interpreter . accumulator ( ) = return_value ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-05 15:15:30 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > NewFunction : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-05 15:14:09 +02:00
{
auto & vm = interpreter . vm ( ) ;
2022-01-18 23:47:11 +00:00
interpreter . accumulator ( ) = ECMAScriptFunctionObject : : create ( interpreter . global_object ( ) , m_function_node . name ( ) , m_function_node . source_text ( ) , m_function_node . body ( ) , m_function_node . parameters ( ) , m_function_node . function_length ( ) , vm . lexical_environment ( ) , vm . running_execution_context ( ) . private_environment , m_function_node . kind ( ) , m_function_node . is_strict_mode ( ) , m_function_node . might_need_arguments_object ( ) , m_function_node . is_arrow_function ( ) ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-05 15:14:09 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > Return : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-05 15:53:36 +02:00
{
2021-06-07 20:58:36 -07:00
interpreter . do_return ( interpreter . accumulator ( ) . value_or ( js_undefined ( ) ) ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-05 15:53:36 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > Increment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-09 11:40:38 +02:00
{
2022-02-07 14:36:45 +01:00
auto old_value = TRY ( interpreter . accumulator ( ) . to_numeric ( interpreter . global_object ( ) ) ) ;
2021-06-09 11:40:38 +02:00
if ( old_value . is_number ( ) )
interpreter . accumulator ( ) = Value ( old_value . as_double ( ) + 1 ) ;
else
interpreter . accumulator ( ) = js_bigint ( interpreter . vm ( ) . heap ( ) , old_value . as_bigint ( ) . big_integer ( ) . plus ( Crypto : : SignedBigInteger { 1 } ) ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-09 11:40:38 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > Decrement : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-09 11:40:38 +02:00
{
2022-02-07 14:36:45 +01:00
auto old_value = TRY ( interpreter . accumulator ( ) . to_numeric ( interpreter . global_object ( ) ) ) ;
2021-06-09 11:40:38 +02:00
if ( old_value . is_number ( ) )
interpreter . accumulator ( ) = Value ( old_value . as_double ( ) - 1 ) ;
else
interpreter . accumulator ( ) = js_bigint ( interpreter . vm ( ) . heap ( ) , old_value . as_bigint ( ) . big_integer ( ) . minus ( Crypto : : SignedBigInteger { 1 } ) ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-09 11:40:38 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > Throw : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-09 18:18:56 +02:00
{
2022-02-07 14:36:45 +01:00
return throw_completion ( interpreter . accumulator ( ) ) ;
2021-06-09 18:18:56 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > EnterUnwindContext : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-10 15:04:38 +02:00
{
interpreter . enter_unwind_context ( m_handler_target , m_finalizer_target ) ;
2021-06-13 20:39:40 +04:30
interpreter . jump ( m_entry_point ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-10 15:04:38 +02:00
}
2021-06-13 20:40:20 +04:30
void EnterUnwindContext : : replace_references_impl ( BasicBlock const & from , BasicBlock const & to )
{
if ( & m_entry_point . block ( ) = = & from )
m_entry_point = Label { to } ;
if ( m_handler_target . has_value ( ) & & & m_handler_target - > block ( ) = = & from )
m_handler_target = Label { to } ;
if ( m_finalizer_target . has_value ( ) & & & m_finalizer_target - > block ( ) = = & from )
m_finalizer_target = Label { to } ;
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > FinishUnwind : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-11-10 22:22:26 +03:30
{
interpreter . leave_unwind_context ( ) ;
interpreter . jump ( m_next_target ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-11-10 22:22:26 +03:30
}
void FinishUnwind : : replace_references_impl ( BasicBlock const & from , BasicBlock const & to )
{
if ( & m_next_target . block ( ) = = & from )
m_next_target = Label { to } ;
}
2022-02-12 19:48:45 +03:30
ThrowCompletionOr < void > LeaveEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
if ( m_mode = = EnvironmentMode : : Lexical )
interpreter . vm ( ) . running_execution_context ( ) . lexical_environment = interpreter . saved_lexical_environment_stack ( ) . take_last ( ) ;
if ( m_mode = = EnvironmentMode : : Var )
interpreter . vm ( ) . running_execution_context ( ) . variable_environment = interpreter . saved_variable_environment_stack ( ) . take_last ( ) ;
return { } ;
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > LeaveUnwindContext : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-10 15:04:38 +02:00
{
interpreter . leave_unwind_context ( ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-10 15:04:38 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > ContinuePendingUnwind : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-10 15:04:38 +02:00
{
2022-02-07 14:36:45 +01:00
return interpreter . continue_pending_unwind ( m_resume_target ) ;
2021-06-10 15:04:38 +02:00
}
2021-06-13 20:40:20 +04:30
void ContinuePendingUnwind : : replace_references_impl ( BasicBlock const & from , BasicBlock const & to )
{
if ( & m_resume_target . block ( ) = = & from )
m_resume_target = Label { to } ;
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > PushDeclarativeEnvironment : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-10 22:12:21 +02:00
{
2022-01-31 13:00:02 +01:00
auto * environment = interpreter . vm ( ) . heap ( ) . allocate_without_global_object < DeclarativeEnvironment > ( interpreter . vm ( ) . lexical_environment ( ) ) ;
2021-07-01 12:24:46 +02:00
interpreter . vm ( ) . running_execution_context ( ) . lexical_environment = environment ;
interpreter . vm ( ) . running_execution_context ( ) . variable_environment = environment ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-10 22:12:21 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > Yield : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-11 01:38:30 +04:30
{
auto yielded_value = interpreter . accumulator ( ) . value_or ( js_undefined ( ) ) ;
2021-06-16 20:52:30 +01:00
auto object = JS : : Object : : create ( interpreter . global_object ( ) , nullptr ) ;
2021-07-06 01:15:50 +03:00
object - > define_direct_property ( " result " , yielded_value , JS : : default_attributes ) ;
2021-06-11 01:38:30 +04:30
if ( m_continuation_label . has_value ( ) )
2021-07-06 01:15:50 +03:00
object - > define_direct_property ( " continuation " , Value ( static_cast < double > ( reinterpret_cast < u64 > ( & m_continuation_label - > block ( ) ) ) ) , JS : : default_attributes ) ;
2021-06-11 01:38:30 +04:30
else
2021-07-06 01:15:50 +03:00
object - > define_direct_property ( " continuation " , Value ( 0 ) , JS : : default_attributes ) ;
2021-06-11 01:38:30 +04:30
interpreter . do_return ( object ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-11 01:38:30 +04:30
}
2021-06-13 20:40:20 +04:30
void Yield : : replace_references_impl ( BasicBlock const & from , BasicBlock const & to )
{
if ( m_continuation_label . has_value ( ) & & & m_continuation_label - > block ( ) = = & from )
m_continuation_label = Label { to } ;
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > GetByValue : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-11 00:35:25 +02:00
{
2022-02-07 14:36:45 +01:00
auto * object = TRY ( interpreter . reg ( m_base ) . to_object ( interpreter . global_object ( ) ) ) ;
auto property_key = TRY ( interpreter . accumulator ( ) . to_property_key ( interpreter . global_object ( ) ) ) ;
interpreter . accumulator ( ) = TRY ( object - > get ( property_key ) ) ;
return { } ;
2021-06-11 00:35:25 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > PutByValue : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-11 00:35:25 +02:00
{
2022-02-07 14:36:45 +01:00
auto * object = TRY ( interpreter . reg ( m_base ) . to_object ( interpreter . global_object ( ) ) ) ;
auto property_key = TRY ( interpreter . reg ( m_property ) . to_property_key ( interpreter . global_object ( ) ) ) ;
TRY ( object - > set ( property_key , interpreter . accumulator ( ) , Object : : ShouldThrowExceptions : : Yes ) ) ;
return { } ;
2021-06-11 00:35:25 +02:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > GetIterator : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-13 13:40:48 -07:00
{
2022-02-07 14:36:45 +01:00
auto iterator = TRY ( get_iterator ( interpreter . global_object ( ) , interpreter . accumulator ( ) ) ) ;
interpreter . accumulator ( ) = iterator_to_object ( interpreter . global_object ( ) , iterator ) ;
return { } ;
2021-06-13 13:40:48 -07:00
}
2022-03-18 20:18:19 +03:30
// 14.7.5.9 EnumerateObjectProperties ( O ), https://tc39.es/ecma262/#sec-enumerate-object-properties
ThrowCompletionOr < void > GetObjectPropertyIterator : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
{
// While the spec does provide an algorithm, it allows us to implement it ourselves so long as we meet the following invariants:
// 1- Returned property keys do not include keys that are Symbols
// 2- Properties of the target object may be deleted during enumeration. A property that is deleted before it is processed by the iterator's next method is ignored
// 3- If new properties are added to the target object during enumeration, the newly added properties are not guaranteed to be processed in the active enumeration
// 4- A property name will be returned by the iterator's next method at most once in any enumeration.
// 5- Enumerating the properties of the target object includes enumerating properties of its prototype, and the prototype of the prototype, and so on, recursively;
// but a property of a prototype is not processed if it has the same name as a property that has already been processed by the iterator's next method.
// 6- The values of [[Enumerable]] attributes are not considered when determining if a property of a prototype object has already been processed.
// 7- The enumerable property names of prototype objects must be obtained by invoking EnumerateObjectProperties passing the prototype object as the argument.
// 8- EnumerateObjectProperties must obtain the own property keys of the target object by calling its [[OwnPropertyKeys]] internal method.
// 9- Property attributes of the target object must be obtained by calling its [[GetOwnProperty]] internal method
// Invariant 3 effectively allows the implementation to ignore newly added keys, and we do so (similar to other implementations).
// Invariants 1 and 6 through 9 are implemented in `enumerable_own_property_names`, which implements the EnumerableOwnPropertyNames AO.
auto * object = TRY ( interpreter . accumulator ( ) . to_object ( interpreter . global_object ( ) ) ) ;
// Note: While the spec doesn't explicitly require these to be ordered, it says that the values should be retrieved via OwnPropertyKeys,
// so we just keep the order consistent anyway.
OrderedHashTable < PropertyKey > properties ;
HashTable < Object * > seen_objects ;
// Collect all keys immediately (invariant no. 5)
for ( auto * object_to_check = object ; object_to_check & & ! seen_objects . contains ( object_to_check ) ; object_to_check = TRY ( object_to_check - > internal_get_prototype_of ( ) ) ) {
seen_objects . set ( object_to_check ) ;
for ( auto & key : TRY ( object_to_check - > enumerable_own_property_names ( Object : : PropertyKind : : Key ) ) ) {
properties . set ( TRY ( PropertyKey : : from_value ( interpreter . global_object ( ) , key ) ) ) ;
}
}
Iterator iterator {
. iterator = object ,
. next_method = NativeFunction : : create (
interpreter . global_object ( ) ,
[ seen_items = HashTable < PropertyKey > ( ) , items = move ( properties ) ] ( VM & vm , GlobalObject & global_object ) mutable - > ThrowCompletionOr < Value > {
auto iterated_object_value = vm . this_value ( global_object ) ;
if ( ! iterated_object_value . is_object ( ) )
return vm . throw_completion < InternalError > ( global_object , " Invalid state for GetObjectPropertyIterator.next " ) ;
auto & iterated_object = iterated_object_value . as_object ( ) ;
auto * result_object = Object : : create ( global_object , nullptr ) ;
while ( true ) {
if ( items . is_empty ( ) ) {
result_object - > define_direct_property ( vm . names . done , JS : : Value ( true ) , default_attributes ) ;
return result_object ;
}
auto it = items . begin ( ) ;
auto key = * it ;
items . remove ( it ) ;
// If the key was already seen, skip over it (invariant no. 4)
auto result = seen_items . set ( key ) ;
if ( result ! = AK : : HashSetResult : : InsertedNewEntry )
continue ;
// If the property is deleted, don't include it (invariant no. 2)
if ( ! TRY ( iterated_object . has_property ( key ) ) )
continue ;
result_object - > define_direct_property ( vm . names . done , JS : : Value ( false ) , default_attributes ) ;
if ( key . is_number ( ) )
result_object - > define_direct_property ( vm . names . value , JS : : Value ( key . as_number ( ) ) , default_attributes ) ;
else if ( key . is_string ( ) )
result_object - > define_direct_property ( vm . names . value , js_string ( vm . heap ( ) , key . as_string ( ) ) , default_attributes ) ;
else
VERIFY_NOT_REACHED ( ) ; // We should not have non-string/number keys.
return result_object ;
}
} ,
1 ,
interpreter . vm ( ) . names . next ) ,
. done = false ,
} ;
interpreter . accumulator ( ) = iterator_to_object ( interpreter . global_object ( ) , move ( iterator ) ) ;
return { } ;
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > IteratorNext : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-13 13:40:48 -07:00
{
2022-02-07 14:36:45 +01:00
auto * iterator_object = TRY ( interpreter . accumulator ( ) . to_object ( interpreter . global_object ( ) ) ) ;
auto iterator = object_to_iterator ( interpreter . global_object ( ) , * iterator_object ) ;
2021-10-20 08:44:30 -04:00
2022-02-07 14:36:45 +01:00
interpreter . accumulator ( ) = TRY ( iterator_next ( interpreter . global_object ( ) , iterator ) ) ;
return { } ;
2021-06-13 13:40:48 -07:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > IteratorResultDone : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-13 13:40:48 -07:00
{
2022-02-07 14:36:45 +01:00
auto * iterator_result = TRY ( interpreter . accumulator ( ) . to_object ( interpreter . global_object ( ) ) ) ;
2021-10-20 09:00:37 -04:00
2022-02-07 14:36:45 +01:00
auto complete = TRY ( iterator_complete ( interpreter . global_object ( ) , * iterator_result ) ) ;
2021-10-20 09:00:37 -04:00
interpreter . accumulator ( ) = Value ( complete ) ;
2022-02-07 14:36:45 +01:00
return { } ;
2021-06-13 13:40:48 -07:00
}
2022-02-07 14:36:45 +01:00
ThrowCompletionOr < void > IteratorResultValue : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-13 13:40:48 -07:00
{
2022-02-07 14:36:45 +01:00
auto * iterator_result = TRY ( interpreter . accumulator ( ) . to_object ( interpreter . global_object ( ) ) ) ;
2021-10-20 09:05:52 -04:00
2022-02-07 14:36:45 +01:00
interpreter . accumulator ( ) = TRY ( iterator_value ( interpreter . global_object ( ) , * iterator_result ) ) ;
return { } ;
2021-06-13 13:40:48 -07:00
}
2022-02-11 22:38:21 +03:30
ThrowCompletionOr < void > NewClass : : execute_impl ( Bytecode : : Interpreter & interpreter ) const
2021-06-30 15:42:13 -03:00
{
2022-02-11 22:38:21 +03:30
auto name = m_class_expression . name ( ) ;
auto scope = interpreter . ast_interpreter_scope ( ) ;
auto & ast_interpreter = scope . interpreter ( ) ;
auto class_object = TRY ( m_class_expression . class_definition_evaluation ( ast_interpreter , interpreter . global_object ( ) , name , name . is_null ( ) ? " " : name ) ) ;
interpreter . accumulator ( ) = class_object ;
return { } ;
2021-06-30 15:42:13 -03:00
}
2021-06-15 18:08:12 +04:30
String Load : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-03 10:46:30 +02:00
{
2021-06-09 11:06:11 +02:00
return String : : formatted ( " Load {} " , m_src ) ;
2021-06-03 10:46:30 +02:00
}
2021-06-15 18:08:12 +04:30
String LoadImmediate : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-07 22:05:09 +02:00
{
2021-06-09 11:06:11 +02:00
return String : : formatted ( " LoadImmediate {} " , m_value ) ;
2021-06-07 20:58:36 -07:00
}
2021-06-15 18:08:12 +04:30
String Store : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-07 20:58:36 -07:00
{
2021-06-09 11:06:11 +02:00
return String : : formatted ( " Store {} " , m_dst ) ;
2021-06-07 22:05:09 +02:00
}
2021-06-15 18:08:12 +04:30
String NewBigInt : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-08 07:59:25 +02:00
{
2021-06-29 17:51:52 +03:00
return String : : formatted ( " NewBigInt \" {} \" " , m_bigint . to_base ( 10 ) ) ;
2021-06-08 07:59:25 +02:00
}
2021-06-15 18:08:12 +04:30
String NewArray : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-08 23:06:52 +02:00
{
StringBuilder builder ;
builder . append ( " NewArray " ) ;
if ( m_element_count ! = 0 ) {
2021-06-09 11:06:11 +02:00
builder . append ( " [ " ) ;
2021-06-08 23:06:52 +02:00
for ( size_t i = 0 ; i < m_element_count ; + + i ) {
builder . appendff ( " {} " , m_elements [ i ] ) ;
if ( i ! = m_element_count - 1 )
builder . append ( ' , ' ) ;
}
builder . append ( ' ] ' ) ;
}
return builder . to_string ( ) ;
}
2021-06-13 14:06:26 -07:00
String IteratorToArray : : to_string_impl ( const Bytecode : : Executable & ) const
{
return " IteratorToArray " ;
}
2021-06-15 18:08:12 +04:30
String NewString : : to_string_impl ( Bytecode : : Executable const & executable ) const
2021-06-03 18:26:32 +02:00
{
2021-06-09 10:02:01 +02:00
return String : : formatted ( " NewString {} ( \" {} \" ) " , m_string , executable . string_table - > get ( m_string ) ) ;
2021-06-03 18:26:32 +02:00
}
2021-06-15 18:08:12 +04:30
String NewObject : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-04 20:30:23 +02:00
{
2021-06-07 20:58:36 -07:00
return " NewObject " ;
}
2021-06-19 17:17:40 -07:00
String NewRegExp : : to_string_impl ( Bytecode : : Executable const & executable ) const
{
return String : : formatted ( " NewRegExp source:{} ( \" {} \" ) flags:{} ( \" {} \" ) " , m_source_index , executable . get_string ( m_source_index ) , m_flags_index , executable . get_string ( m_flags_index ) ) ;
}
2021-06-13 15:30:32 -07:00
String CopyObjectExcludingProperties : : to_string_impl ( const Bytecode : : Executable & ) const
{
StringBuilder builder ;
builder . appendff ( " CopyObjectExcludingProperties from:{} " , m_from_object ) ;
if ( m_excluded_names_count ! = 0 ) {
builder . append ( " excluding:[ " ) ;
for ( size_t i = 0 ; i < m_excluded_names_count ; + + i ) {
builder . appendff ( " {} " , m_excluded_names [ i ] ) ;
if ( i ! = m_excluded_names_count - 1 )
builder . append ( ' , ' ) ;
}
builder . append ( ' ] ' ) ;
}
return builder . to_string ( ) ;
}
2021-06-15 18:08:12 +04:30
String ConcatString : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-07 20:58:36 -07:00
{
2021-06-09 11:06:11 +02:00
return String : : formatted ( " ConcatString {} " , m_lhs ) ;
2021-06-04 20:30:23 +02:00
}
2021-06-15 18:08:12 +04:30
String GetVariable : : to_string_impl ( Bytecode : : Executable const & executable ) const
2021-06-03 18:26:32 +02:00
{
2021-10-24 15:34:30 +02:00
return String : : formatted ( " GetVariable {} ({}) " , m_identifier , executable . identifier_table - > get ( m_identifier ) ) ;
2021-06-03 18:26:32 +02:00
}
2022-02-12 19:48:45 +03:30
String CreateEnvironment : : to_string_impl ( Bytecode : : Executable const & ) const
{
auto mode_string = m_mode = = EnvironmentMode : : Lexical
? " Lexical "
: " Variable " ;
return String : : formatted ( " CreateEnvironment mode:{} " , mode_string ) ;
}
String CreateVariable : : to_string_impl ( Bytecode : : Executable const & executable ) const
{
auto mode_string = m_mode = = EnvironmentMode : : Lexical ? " Lexical " : " Variable " ;
return String : : formatted ( " CreateVariable env:{} immutable:{} {} ({}) " , mode_string , m_is_immutable , m_identifier , executable . identifier_table - > get ( m_identifier ) ) ;
}
2022-03-13 16:01:18 +03:30
String EnterObjectEnvironment : : to_string_impl ( const Executable & ) const
{
return String : : formatted ( " EnterObjectEnvironment " ) ;
}
2021-06-15 18:08:12 +04:30
String SetVariable : : to_string_impl ( Bytecode : : Executable const & executable ) const
2021-06-03 18:26:32 +02:00
{
2022-02-12 19:48:45 +03:30
auto initialization_mode_name = m_initialization_mode = = InitializationMode : : Initialize ? " Initialize "
: m_initialization_mode = = InitializationMode : : Set ? " Set "
: " InitializeOrSet " ;
auto mode_string = m_mode = = EnvironmentMode : : Lexical ? " Lexical " : " Variable " ;
return String : : formatted ( " SetVariable env:{} init:{} {} ({}) " , mode_string , initialization_mode_name , m_identifier , executable . identifier_table - > get ( m_identifier ) ) ;
2021-06-03 18:26:32 +02:00
}
2021-06-15 18:08:12 +04:30
String PutById : : to_string_impl ( Bytecode : : Executable const & executable ) const
2021-06-04 20:47:07 +02:00
{
2021-10-24 15:34:30 +02:00
return String : : formatted ( " PutById base:{}, property:{} ({}) " , m_base , m_property , executable . identifier_table - > get ( m_property ) ) ;
2021-06-04 20:47:07 +02:00
}
2021-06-15 18:08:12 +04:30
String GetById : : to_string_impl ( Bytecode : : Executable const & executable ) const
2021-06-04 21:03:53 +02:00
{
2021-10-24 15:34:30 +02:00
return String : : formatted ( " GetById {} ({}) " , m_property , executable . identifier_table - > get ( m_property ) ) ;
2021-06-04 21:03:53 +02:00
}
2021-06-15 18:08:12 +04:30
String Jump : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-04 12:07:38 +02:00
{
2021-06-09 06:49:58 +04:30
if ( m_true_target . has_value ( ) )
return String : : formatted ( " Jump {} " , * m_true_target ) ;
return String : : formatted ( " Jump <empty> " ) ;
2021-06-04 12:07:38 +02:00
}
2021-06-15 18:08:12 +04:30
String JumpConditional : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-04 12:20:44 +02:00
{
2021-06-09 06:49:58 +04:30
auto true_string = m_true_target . has_value ( ) ? String : : formatted ( " {} " , * m_true_target ) : " <empty> " ;
auto false_string = m_false_target . has_value ( ) ? String : : formatted ( " {} " , * m_false_target ) : " <empty> " ;
return String : : formatted ( " JumpConditional true:{} false:{} " , true_string , false_string ) ;
2021-06-04 12:20:44 +02:00
}
2021-06-15 18:08:12 +04:30
String JumpNullish : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-08 02:18:47 +02:00
{
2021-06-09 06:49:58 +04:30
auto true_string = m_true_target . has_value ( ) ? String : : formatted ( " {} " , * m_true_target ) : " <empty> " ;
auto false_string = m_false_target . has_value ( ) ? String : : formatted ( " {} " , * m_false_target ) : " <empty> " ;
return String : : formatted ( " JumpNullish null:{} nonnull:{} " , true_string , false_string ) ;
2021-06-08 02:18:47 +02:00
}
2021-06-13 12:24:40 -07:00
String JumpUndefined : : to_string_impl ( Bytecode : : Executable const & ) const
{
auto true_string = m_true_target . has_value ( ) ? String : : formatted ( " {} " , * m_true_target ) : " <empty> " ;
auto false_string = m_false_target . has_value ( ) ? String : : formatted ( " {} " , * m_false_target ) : " <empty> " ;
return String : : formatted ( " JumpUndefined undefined:{} not undefined:{} " , true_string , false_string ) ;
}
2021-06-15 18:08:12 +04:30
String Call : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-05 15:15:30 +02:00
{
StringBuilder builder ;
2021-06-07 20:58:36 -07:00
builder . appendff ( " Call callee:{}, this:{} " , m_callee , m_this_value ) ;
2021-06-07 15:12:43 +02:00
if ( m_argument_count ! = 0 ) {
2021-06-05 15:15:30 +02:00
builder . append ( " , arguments:[ " ) ;
2021-06-07 15:12:43 +02:00
for ( size_t i = 0 ; i < m_argument_count ; + + i ) {
2021-06-05 15:15:30 +02:00
builder . appendff ( " {} " , m_arguments [ i ] ) ;
2021-06-07 15:12:43 +02:00
if ( i ! = m_argument_count - 1 )
2021-06-05 15:15:30 +02:00
builder . append ( ' , ' ) ;
}
builder . append ( ' ] ' ) ;
}
return builder . to_string ( ) ;
}
2021-06-15 18:08:12 +04:30
String NewFunction : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-05 15:14:09 +02:00
{
2021-06-10 00:49:23 +02:00
return " NewFunction " ;
2021-06-05 15:14:09 +02:00
}
2021-06-30 15:42:13 -03:00
String NewClass : : to_string_impl ( Bytecode : : Executable const & ) const
{
return " NewClass " ;
}
2021-06-15 18:08:12 +04:30
String Return : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-05 15:53:36 +02:00
{
return " Return " ;
}
2021-06-15 18:08:12 +04:30
String Increment : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-09 11:40:38 +02:00
{
return " Increment " ;
}
2021-06-15 18:08:12 +04:30
String Decrement : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-09 11:40:38 +02:00
{
return " Decrement " ;
}
2021-06-15 18:08:12 +04:30
String Throw : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-09 18:18:56 +02:00
{
return " Throw " ;
}
2021-06-15 18:08:12 +04:30
String EnterUnwindContext : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-10 15:04:38 +02:00
{
auto handler_string = m_handler_target . has_value ( ) ? String : : formatted ( " {} " , * m_handler_target ) : " <empty> " ;
auto finalizer_string = m_finalizer_target . has_value ( ) ? String : : formatted ( " {} " , * m_finalizer_target ) : " <empty> " ;
2021-06-13 20:39:40 +04:30
return String : : formatted ( " EnterUnwindContext handler:{} finalizer:{} entry:{} " , handler_string , finalizer_string , m_entry_point ) ;
2021-06-10 15:04:38 +02:00
}
2021-11-10 22:22:26 +03:30
String FinishUnwind : : to_string_impl ( const Bytecode : : Executable & ) const
{
return String : : formatted ( " FinishUnwind next:{} " , m_next_target ) ;
}
2022-02-12 19:48:45 +03:30
String LeaveEnvironment : : to_string_impl ( Bytecode : : Executable const & ) const
{
auto mode_string = m_mode = = EnvironmentMode : : Lexical
? " Lexical "
: " Variable " ;
return String : : formatted ( " LeaveEnvironment env:{} " , mode_string ) ;
}
2021-06-15 18:08:12 +04:30
String LeaveUnwindContext : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-10 15:04:38 +02:00
{
return " LeaveUnwindContext " ;
}
2021-06-15 18:08:12 +04:30
String ContinuePendingUnwind : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-10 15:04:38 +02:00
{
return String : : formatted ( " ContinuePendingUnwind resume:{} " , m_resume_target ) ;
}
2021-07-01 12:24:46 +02:00
String PushDeclarativeEnvironment : : to_string_impl ( const Bytecode : : Executable & executable ) const
2021-06-10 22:12:21 +02:00
{
StringBuilder builder ;
2021-07-01 12:24:46 +02:00
builder . append ( " PushDeclarativeEnvironment " ) ;
2021-06-10 22:12:21 +02:00
if ( ! m_variables . is_empty ( ) ) {
builder . append ( " { " ) ;
Vector < String > names ;
for ( auto & it : m_variables )
names . append ( executable . get_string ( it . key ) ) ;
builder . join ( " , " , names ) ;
builder . append ( " } " ) ;
}
return builder . to_string ( ) ;
}
2021-06-15 18:08:12 +04:30
String Yield : : to_string_impl ( Bytecode : : Executable const & ) const
2021-06-11 01:38:30 +04:30
{
if ( m_continuation_label . has_value ( ) )
return String : : formatted ( " Yield continuation:@{} " , m_continuation_label - > block ( ) . name ( ) ) ;
return String : : formatted ( " Yield return " ) ;
}
2021-06-15 18:08:12 +04:30
String GetByValue : : to_string_impl ( const Bytecode : : Executable & ) const
2021-06-11 00:35:25 +02:00
{
return String : : formatted ( " GetByValue base:{} " , m_base ) ;
}
2021-06-15 18:08:12 +04:30
String PutByValue : : to_string_impl ( const Bytecode : : Executable & ) const
2021-06-11 00:35:25 +02:00
{
return String : : formatted ( " PutByValue base:{}, property:{} " , m_base , m_property ) ;
}
2021-06-13 13:40:48 -07:00
String GetIterator : : to_string_impl ( Executable const & ) const
{
return " GetIterator " ;
}
2022-03-18 20:18:19 +03:30
String GetObjectPropertyIterator : : to_string_impl ( const Bytecode : : Executable & ) const
{
return " GetObjectPropertyIterator " ;
}
2021-06-13 13:40:48 -07:00
String IteratorNext : : to_string_impl ( Executable const & ) const
{
return " IteratorNext " ;
}
String IteratorResultDone : : to_string_impl ( Executable const & ) const
{
return " IteratorResultDone " ;
}
String IteratorResultValue : : to_string_impl ( Executable const & ) const
{
return " IteratorResultValue " ;
}
2021-10-24 14:43:00 +02:00
String ResolveThisBinding : : to_string_impl ( Bytecode : : Executable const & ) const
{
return " ResolveThisBinding " sv ;
}
2022-03-19 19:40:21 +00:00
String GetNewTarget : : to_string_impl ( Bytecode : : Executable const & ) const
{
return " GetNewTarget " sv ;
}
2021-06-03 10:46:30 +02:00
}