2021-06-04 11:31:13 +02:00
/*
2023-02-19 22:07:52 +01:00
* Copyright ( c ) 2021 - 2023 , Andreas Kling < kling @ serenityos . org >
2021-06-07 21:13:37 +01:00
* Copyright ( c ) 2021 , Linus Groh < linusg @ serenityos . org >
2021-06-09 18:18:56 +02:00
* Copyright ( c ) 2021 , Gunnar Beutner < gbeutner @ serenityos . org >
2021-06-11 00:36:16 +02:00
* Copyright ( c ) 2021 , Marcin Gasperowicz < xnooga @ gmail . com >
2021-06-04 11:31:13 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-09-09 15:23:02 +02:00
# include <AK/Find.h>
2021-06-04 11:31:13 +02:00
# include <LibJS/AST.h>
# include <LibJS/Bytecode/Generator.h>
# include <LibJS/Bytecode/Instruction.h>
# include <LibJS/Bytecode/Op.h>
# include <LibJS/Bytecode/Register.h>
2021-06-10 22:12:21 +02:00
# include <LibJS/Bytecode/StringTable.h>
2021-07-01 12:24:46 +02:00
# include <LibJS/Runtime/Environment.h>
2022-12-09 18:48:57 +00:00
# include <LibJS/Runtime/ErrorTypes.h>
2021-06-04 11:31:13 +02:00
namespace JS {
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ASTNode : : generate_bytecode ( Bytecode : : Generator & ) const
2021-06-04 11:31:13 +02:00
{
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Missing generate_bytecode() " sv ,
} ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ScopeNode : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2023-06-16 16:34:47 +02:00
bool did_create_lexical_environment = false ;
2023-06-25 07:37:24 +02:00
if ( is < BlockStatement > ( * this ) ) {
2022-02-12 19:48:45 +03:30
if ( has_lexical_declarations ( ) ) {
2023-06-16 16:34:47 +02:00
generator . block_declaration_instantiation ( * this ) ;
did_create_lexical_environment = true ;
2022-02-12 19:48:45 +03:30
}
} else if ( is < Program > ( * this ) ) {
2023-06-15 12:36:57 +02:00
// GlobalDeclarationInstantiation is handled by the C++ AO.
2022-02-12 19:48:45 +03:30
} else {
2023-06-15 09:14:25 +02:00
// FunctionDeclarationInstantiation is handled by the C++ AO.
2022-02-12 19:48:45 +03:30
}
2021-06-09 19:57:18 +02:00
for ( auto & child : children ( ) ) {
2023-03-06 14:17:01 +01:00
TRY ( child - > generate_bytecode ( generator ) ) ;
2021-06-09 19:57:18 +02:00
if ( generator . is_current_block_terminated ( ) )
break ;
}
2022-02-12 19:54:08 +03:30
2023-06-16 16:34:47 +02:00
if ( did_create_lexical_environment )
2022-02-12 19:48:45 +03:30
generator . end_variable_scope ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > EmptyStatement : : generate_bytecode ( Bytecode : : Generator & ) const
2021-06-07 20:47:26 +02:00
{
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 20:47:26 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ExpressionStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2022-02-12 19:54:08 +03:30
return m_expression - > generate_bytecode ( generator ) ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > BinaryExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( m_lhs - > generate_bytecode ( generator ) ) ;
2021-06-07 20:58:36 -07:00
auto lhs_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( lhs_reg ) ;
2021-06-04 11:31:13 +02:00
2022-02-12 19:54:08 +03:30
TRY ( m_rhs - > generate_bytecode ( generator ) ) ;
2021-06-04 11:31:13 +02:00
switch ( m_op ) {
case BinaryOp : : Addition :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Add > ( lhs_reg ) ;
break ;
2021-06-04 11:31:13 +02:00
case BinaryOp : : Subtraction :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Sub > ( lhs_reg ) ;
break ;
2021-06-07 19:17:20 +02:00
case BinaryOp : : Multiplication :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Mul > ( lhs_reg ) ;
break ;
2021-06-07 19:17:20 +02:00
case BinaryOp : : Division :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Div > ( lhs_reg ) ;
break ;
2021-06-07 19:37:23 +02:00
case BinaryOp : : Modulo :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Mod > ( lhs_reg ) ;
break ;
2021-06-07 19:37:23 +02:00
case BinaryOp : : Exponentiation :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Exp > ( lhs_reg ) ;
break ;
2021-06-07 19:57:38 +02:00
case BinaryOp : : GreaterThan :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : GreaterThan > ( lhs_reg ) ;
break ;
2021-06-07 19:57:38 +02:00
case BinaryOp : : GreaterThanEquals :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : GreaterThanEquals > ( lhs_reg ) ;
break ;
2021-06-04 12:03:57 +02:00
case BinaryOp : : LessThan :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LessThan > ( lhs_reg ) ;
break ;
2021-06-07 19:57:38 +02:00
case BinaryOp : : LessThanEquals :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LessThanEquals > ( lhs_reg ) ;
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : LooselyInequals :
generator . emit < Bytecode : : Op : : LooselyInequals > ( lhs_reg ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : LooselyEquals :
generator . emit < Bytecode : : Op : : LooselyEquals > ( lhs_reg ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : StrictlyInequals :
generator . emit < Bytecode : : Op : : StrictlyInequals > ( lhs_reg ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : StrictlyEquals :
generator . emit < Bytecode : : Op : : StrictlyEquals > ( lhs_reg ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:16:04 +01:00
case BinaryOp : : BitwiseAnd :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : BitwiseAnd > ( lhs_reg ) ;
break ;
2021-06-07 19:16:04 +01:00
case BinaryOp : : BitwiseOr :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : BitwiseOr > ( lhs_reg ) ;
break ;
2021-06-07 19:16:04 +01:00
case BinaryOp : : BitwiseXor :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : BitwiseXor > ( lhs_reg ) ;
break ;
2021-06-07 20:14:12 +01:00
case BinaryOp : : LeftShift :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LeftShift > ( lhs_reg ) ;
break ;
2021-06-07 20:14:12 +01:00
case BinaryOp : : RightShift :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : RightShift > ( lhs_reg ) ;
break ;
2021-06-07 20:14:12 +01:00
case BinaryOp : : UnsignedRightShift :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : UnsignedRightShift > ( lhs_reg ) ;
break ;
2021-06-07 21:13:37 +01:00
case BinaryOp : : In :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : In > ( lhs_reg ) ;
break ;
2021-06-07 21:18:19 +01:00
case BinaryOp : : InstanceOf :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : InstanceOf > ( lhs_reg ) ;
break ;
2021-06-04 11:31:13 +02:00
default :
2021-06-07 21:18:19 +01:00
VERIFY_NOT_REACHED ( ) ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > LogicalExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 02:18:47 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( m_lhs - > generate_bytecode ( generator ) ) ;
2021-06-08 02:18:47 +02:00
2021-06-09 06:49:58 +04:30
// lhs
// jump op (true) end (false) rhs
// rhs
// jump always (true) end
// end
auto & rhs_block = generator . make_block ( ) ;
auto & end_block = generator . make_block ( ) ;
2021-06-08 02:18:47 +02:00
switch ( m_op ) {
case LogicalOp : : And :
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { rhs_block } ,
Bytecode : : Label { end_block } ) ;
2021-06-08 02:18:47 +02:00
break ;
case LogicalOp : : Or :
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { end_block } ,
Bytecode : : Label { rhs_block } ) ;
2021-06-08 02:18:47 +02:00
break ;
case LogicalOp : : NullishCoalescing :
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpNullish > ( ) . set_targets (
Bytecode : : Label { rhs_block } ,
Bytecode : : Label { end_block } ) ;
2021-06-08 02:18:47 +02:00
break ;
default :
VERIFY_NOT_REACHED ( ) ;
}
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( rhs_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_rhs - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { end_block } ,
{ } ) ;
generator . switch_to_basic_block ( end_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 02:18:47 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > UnaryExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-07 19:53:47 +01:00
{
2022-03-27 19:50:09 +01:00
if ( m_op = = UnaryOp : : Delete )
return generator . emit_delete_reference ( m_lhs ) ;
2022-06-11 23:12:22 +01:00
// Typeof needs some special handling for when the LHS is an Identifier. Namely, it shouldn't throw on unresolvable references, but instead return "undefined".
if ( m_op ! = UnaryOp : : Typeof )
TRY ( m_lhs - > generate_bytecode ( generator ) ) ;
2021-06-07 19:53:47 +01:00
switch ( m_op ) {
case UnaryOp : : BitwiseNot :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : BitwiseNot > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Not :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Not > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Plus :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : UnaryPlus > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Minus :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : UnaryMinus > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Typeof :
2022-06-11 23:12:22 +01:00
if ( is < Identifier > ( * m_lhs ) ) {
auto & identifier = static_cast < Identifier const & > ( * m_lhs ) ;
generator . emit < Bytecode : : Op : : TypeofVariable > ( generator . intern_identifier ( identifier . string ( ) ) ) ;
break ;
}
TRY ( m_lhs - > generate_bytecode ( generator ) ) ;
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Typeof > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Void :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
break ;
2022-03-27 19:50:09 +01:00
case UnaryOp : : Delete : // Delete is implemented above.
2021-06-07 19:53:47 +01:00
default :
2022-03-27 19:50:09 +01:00
VERIFY_NOT_REACHED ( ) ;
2021-06-07 19:53:47 +01:00
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 19:53:47 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > NumericLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( m_value ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > BooleanLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-07 20:22:15 +02:00
{
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value ( m_value ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 20:22:15 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > NullLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-07 20:22:15 +02:00
{
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_null ( ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 20:22:15 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > BigIntLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 07:59:25 +02:00
{
2022-10-19 19:17:58 +02:00
// 1. Return the NumericValue of NumericLiteral as defined in 12.8.3.
auto integer = [ & ] {
if ( m_value [ 0 ] = = ' 0 ' & & m_value . length ( ) > = 3 )
if ( m_value [ 1 ] = = ' x ' | | m_value [ 1 ] = = ' X ' )
return Crypto : : SignedBigInteger : : from_base ( 16 , m_value . substring ( 2 , m_value . length ( ) - 3 ) ) ;
if ( m_value [ 1 ] = = ' o ' | | m_value [ 1 ] = = ' O ' )
return Crypto : : SignedBigInteger : : from_base ( 8 , m_value . substring ( 2 , m_value . length ( ) - 3 ) ) ;
if ( m_value [ 1 ] = = ' b ' | | m_value [ 1 ] = = ' B ' )
return Crypto : : SignedBigInteger : : from_base ( 2 , m_value . substring ( 2 , m_value . length ( ) - 3 ) ) ;
return Crypto : : SignedBigInteger : : from_base ( 10 , m_value . substring ( 0 , m_value . length ( ) - 1 ) ) ;
} ( ) ;
generator . emit < Bytecode : : Op : : NewBigInt > ( integer ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 07:59:25 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > StringLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2021-06-09 10:02:01 +02:00
generator . emit < Bytecode : : Op : : NewString > ( generator . intern_string ( m_value ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > RegExpLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-19 17:17:40 -07:00
{
auto source_index = generator . intern_string ( m_pattern ) ;
auto flags_index = generator . intern_string ( m_flags ) ;
generator . emit < Bytecode : : Op : : NewRegExp > ( source_index , flags_index ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-19 17:17:40 -07:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > Identifier : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2021-10-24 15:34:30 +02:00
generator . emit < Bytecode : : Op : : GetVariable > ( generator . intern_identifier ( m_string ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2023-02-05 19:02:54 +00:00
static Bytecode : : CodeGenerationErrorOr < void > arguments_to_array_for_call ( Bytecode : : Generator & generator , ReadonlySpan < CallExpression : : Argument > arguments )
2022-09-09 16:05:40 +02:00
{
if ( arguments . is_empty ( ) ) {
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
return { } ;
}
auto first_spread = find_if ( arguments . begin ( ) , arguments . end ( ) , [ ] ( auto el ) { return el . is_spread ; } ) ;
Bytecode : : Register args_start_reg { 0 } ;
for ( auto it = arguments . begin ( ) ; it ! = first_spread ; + + it ) {
auto reg = generator . allocate_register ( ) ;
if ( args_start_reg . index ( ) = = 0 )
args_start_reg = reg ;
}
u32 i = 0 ;
for ( auto it = arguments . begin ( ) ; it ! = first_spread ; + + it , + + i ) {
VERIFY ( it - > is_spread = = false ) ;
Bytecode : : Register reg { args_start_reg . index ( ) + i } ;
TRY ( it - > value - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : Store > ( reg ) ;
}
if ( first_spread . index ( ) ! = 0 )
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2u , AK : : Array { args_start_reg , Bytecode : : Register { args_start_reg . index ( ) + static_cast < u32 > ( first_spread . index ( ) - 1 ) } } ) ;
else
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
if ( first_spread ! = arguments . end ( ) ) {
auto array_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( array_reg ) ;
for ( auto it = first_spread ; it ! = arguments . end ( ) ; + + it ) {
TRY ( it - > value - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : Append > ( array_reg , it - > is_spread ) ;
}
generator . emit < Bytecode : : Op : : Load > ( array_reg ) ;
}
return { } ;
}
2022-08-30 18:03:02 +02:00
Bytecode : : CodeGenerationErrorOr < void > SuperCall : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
if ( m_is_synthetic = = IsPartOfSyntheticConstructor : : Yes ) {
// NOTE: This is the case where we have a fake constructor(...args) { super(...args); } which
// shouldn't call @@iterator of %Array.prototype%.
VERIFY ( m_arguments . size ( ) = = 1 ) ;
VERIFY ( m_arguments [ 0 ] . is_spread ) ;
auto const & argument = m_arguments [ 0 ] ;
// This generates a single argument, which will be implicitly passed in accumulator
MUST ( argument . value - > generate_bytecode ( generator ) ) ;
} else {
2022-09-09 16:05:40 +02:00
TRY ( arguments_to_array_for_call ( generator , m_arguments ) ) ;
2022-08-30 18:03:02 +02:00
}
2022-09-07 23:39:43 +02:00
generator . emit < Bytecode : : Op : : SuperCall > ( m_is_synthetic = = IsPartOfSyntheticConstructor : : Yes ) ;
2022-08-30 18:03:02 +02:00
return { } ;
}
2023-06-24 20:29:30 +02:00
static Bytecode : : CodeGenerationErrorOr < void > generate_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode , Bytecode : : Register const & value_reg , bool create_variables ) ;
2022-07-17 19:24:37 +01:00
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > AssignmentExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2021-10-25 15:29:52 +02:00
if ( m_op = = AssignmentOp : : Assignment ) {
2022-07-17 19:23:52 +01:00
// AssignmentExpression : LeftHandSideExpression = AssignmentExpression
return m_lhs . visit (
// 1. If LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral, then
2023-02-19 22:07:52 +01:00
[ & ] ( NonnullRefPtr < Expression const > const & lhs ) - > Bytecode : : CodeGenerationErrorOr < void > {
2022-07-17 19:23:52 +01:00
// a. Let lref be the result of evaluating LeftHandSideExpression.
// b. ReturnIfAbrupt(lref).
Optional < Bytecode : : Register > base_object_register ;
Optional < Bytecode : : Register > computed_property_register ;
if ( is < MemberExpression > ( * lhs ) ) {
auto & expression = static_cast < MemberExpression const & > ( * lhs ) ;
TRY ( expression . object ( ) . generate_bytecode ( generator ) ) ;
base_object_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( * base_object_register ) ;
if ( expression . is_computed ( ) ) {
TRY ( expression . property ( ) . generate_bytecode ( generator ) ) ;
computed_property_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( * computed_property_register ) ;
// To be continued later with PutByValue.
} else if ( expression . property ( ) . is_identifier ( ) ) {
// Do nothing, this will be handled by PutById later.
2023-06-23 08:16:17 +02:00
} else if ( expression . property ( ) . is_private_identifier ( ) ) {
// Do nothing, this will be handled by PutPrivateById later.
2022-07-17 19:23:52 +01:00
} else {
return Bytecode : : CodeGenerationError {
& expression ,
" Unimplemented non-computed member expression " sv
} ;
}
} else if ( is < Identifier > ( * lhs ) ) {
// NOTE: For Identifiers, we cannot perform GetVariable and then write into the reference it retrieves, only SetVariable can do this.
// FIXME: However, this breaks spec as we are doing variable lookup after evaluating the RHS. This is observable in an object environment, where we visibly perform HasOwnProperty and Get(@@unscopables) on the binded object.
} else {
TRY ( lhs - > generate_bytecode ( generator ) ) ;
}
// FIXME: c. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
// i. Let rval be ? NamedEvaluation of AssignmentExpression with argument lref.[[ReferencedName]].
// d. Else,
// i. Let rref be the result of evaluating AssignmentExpression.
// ii. Let rval be ? GetValue(rref).
2023-06-23 14:27:42 +02:00
if ( lhs - > is_identifier ( ) ) {
TRY ( generator . emit_named_evaluation_if_anonymous_function ( * m_rhs , static_cast < Identifier const & > ( * lhs ) . string ( ) ) ) ;
} else {
TRY ( m_rhs - > generate_bytecode ( generator ) ) ;
}
2022-07-17 19:23:52 +01:00
// e. Perform ? PutValue(lref, rval).
if ( is < Identifier > ( * lhs ) ) {
auto & identifier = static_cast < Identifier const & > ( * lhs ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( identifier . string ( ) ) ) ;
} else if ( is < MemberExpression > ( * lhs ) ) {
auto & expression = static_cast < MemberExpression const & > ( * lhs ) ;
if ( expression . is_computed ( ) ) {
generator . emit < Bytecode : : Op : : PutByValue > ( * base_object_register , * computed_property_register ) ;
} else if ( expression . property ( ) . is_identifier ( ) ) {
auto identifier_table_ref = generator . intern_identifier ( verify_cast < Identifier > ( expression . property ( ) ) . string ( ) ) ;
generator . emit < Bytecode : : Op : : PutById > ( * base_object_register , identifier_table_ref ) ;
2023-06-23 08:16:17 +02:00
} else if ( expression . property ( ) . is_private_identifier ( ) ) {
auto identifier_table_ref = generator . intern_identifier ( verify_cast < PrivateIdentifier > ( expression . property ( ) ) . string ( ) ) ;
generator . emit < Bytecode : : Op : : PutPrivateById > ( * base_object_register , identifier_table_ref ) ;
2022-07-17 19:23:52 +01:00
} else {
return Bytecode : : CodeGenerationError {
& expression ,
" Unimplemented non-computed member expression " sv
} ;
}
} else {
return Bytecode : : CodeGenerationError {
lhs ,
" Unimplemented/invalid node used a reference " sv
} ;
}
// f. Return rval.
// NOTE: This is already in the accumulator.
return { } ;
} ,
// 2. Let assignmentPattern be the AssignmentPattern that is covered by LeftHandSideExpression.
2023-02-19 22:07:52 +01:00
[ & ] ( NonnullRefPtr < BindingPattern const > const & pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
2022-07-17 19:24:37 +01:00
// 3. Let rref be the result of evaluating AssignmentExpression.
// 4. Let rval be ? GetValue(rref).
TRY ( m_rhs - > generate_bytecode ( generator ) ) ;
auto value_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( value_register ) ;
// 5. Perform ? DestructuringAssignmentEvaluation of assignmentPattern with argument rval.
2023-06-24 20:29:30 +02:00
TRY ( generate_binding_pattern_bytecode ( generator , pattern , Bytecode : : Op : : SetVariable : : InitializationMode : : Set , value_register , false ) ) ;
2022-07-17 19:24:37 +01:00
// 6. Return rval.
generator . emit < Bytecode : : Op : : Load > ( value_register ) ;
return { } ;
2022-07-17 19:23:52 +01:00
} ) ;
2021-10-25 15:29:52 +02:00
}
2021-06-07 20:12:38 +01:00
2023-02-19 22:07:52 +01:00
VERIFY ( m_lhs . has < NonnullRefPtr < Expression const > > ( ) ) ;
auto & lhs = m_lhs . get < NonnullRefPtr < Expression const > > ( ) ;
2022-07-17 19:23:52 +01:00
2022-02-12 19:54:08 +03:30
TRY ( generator . emit_load_from_reference ( lhs ) ) ;
2021-06-07 20:12:38 +01:00
2021-10-25 15:29:52 +02:00
Bytecode : : BasicBlock * rhs_block_ptr { nullptr } ;
Bytecode : : BasicBlock * end_block_ptr { nullptr } ;
2021-06-07 20:12:38 +01:00
2021-10-25 15:29:52 +02:00
// Logical assignments short circuit.
if ( m_op = = AssignmentOp : : AndAssignment ) { // &&=
rhs_block_ptr = & generator . make_block ( ) ;
end_block_ptr = & generator . make_block ( ) ;
2021-06-09 21:14:31 +01:00
2021-10-25 15:29:52 +02:00
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { * rhs_block_ptr } ,
Bytecode : : Label { * end_block_ptr } ) ;
} else if ( m_op = = AssignmentOp : : OrAssignment ) { // ||=
rhs_block_ptr = & generator . make_block ( ) ;
end_block_ptr = & generator . make_block ( ) ;
2021-06-09 21:14:31 +01:00
2021-10-25 15:29:52 +02:00
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { * end_block_ptr } ,
Bytecode : : Label { * rhs_block_ptr } ) ;
} else if ( m_op = = AssignmentOp : : NullishAssignment ) { // ??=
rhs_block_ptr = & generator . make_block ( ) ;
end_block_ptr = & generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpNullish > ( ) . set_targets (
Bytecode : : Label { * rhs_block_ptr } ,
Bytecode : : Label { * end_block_ptr } ) ;
2021-06-04 11:31:13 +02:00
}
2021-10-25 15:29:52 +02:00
if ( rhs_block_ptr )
generator . switch_to_basic_block ( * rhs_block_ptr ) ;
// lhs_reg is a part of the rhs_block because the store isn't necessary
// if the logical assignment condition fails.
auto lhs_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( lhs_reg ) ;
2023-06-26 15:26:46 +02:00
if ( lhs - > is_identifier ( ) )
TRY ( generator . emit_named_evaluation_if_anonymous_function ( * m_rhs , static_cast < Identifier const & > ( * lhs ) . string ( ) ) ) ;
else
TRY ( m_rhs - > generate_bytecode ( generator ) ) ;
2021-10-25 15:29:52 +02:00
switch ( m_op ) {
case AssignmentOp : : AdditionAssignment :
generator . emit < Bytecode : : Op : : Add > ( lhs_reg ) ;
break ;
case AssignmentOp : : SubtractionAssignment :
generator . emit < Bytecode : : Op : : Sub > ( lhs_reg ) ;
break ;
case AssignmentOp : : MultiplicationAssignment :
generator . emit < Bytecode : : Op : : Mul > ( lhs_reg ) ;
break ;
case AssignmentOp : : DivisionAssignment :
generator . emit < Bytecode : : Op : : Div > ( lhs_reg ) ;
break ;
case AssignmentOp : : ModuloAssignment :
generator . emit < Bytecode : : Op : : Mod > ( lhs_reg ) ;
break ;
case AssignmentOp : : ExponentiationAssignment :
generator . emit < Bytecode : : Op : : Exp > ( lhs_reg ) ;
break ;
case AssignmentOp : : BitwiseAndAssignment :
generator . emit < Bytecode : : Op : : BitwiseAnd > ( lhs_reg ) ;
break ;
case AssignmentOp : : BitwiseOrAssignment :
generator . emit < Bytecode : : Op : : BitwiseOr > ( lhs_reg ) ;
break ;
case AssignmentOp : : BitwiseXorAssignment :
generator . emit < Bytecode : : Op : : BitwiseXor > ( lhs_reg ) ;
break ;
case AssignmentOp : : LeftShiftAssignment :
generator . emit < Bytecode : : Op : : LeftShift > ( lhs_reg ) ;
break ;
case AssignmentOp : : RightShiftAssignment :
generator . emit < Bytecode : : Op : : RightShift > ( lhs_reg ) ;
break ;
case AssignmentOp : : UnsignedRightShiftAssignment :
generator . emit < Bytecode : : Op : : UnsignedRightShift > ( lhs_reg ) ;
break ;
case AssignmentOp : : AndAssignment :
case AssignmentOp : : OrAssignment :
case AssignmentOp : : NullishAssignment :
break ; // These are handled above.
default :
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented operation " sv ,
} ;
2021-06-04 20:47:07 +02:00
}
2022-02-12 19:54:08 +03:30
TRY ( generator . emit_store_to_reference ( lhs ) ) ;
2021-10-25 15:29:52 +02:00
if ( end_block_ptr ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { * end_block_ptr } ,
{ } ) ;
generator . switch_to_basic_block ( * end_block_ptr ) ;
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-06-11 23:09:37 +01:00
// 14.13.3 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-labelled-statements-runtime-semantics-evaluation
// LabelledStatement : LabelIdentifier : LabelledItem
Bytecode : : CodeGenerationErrorOr < void > LabelledStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
// Return ? LabelledEvaluation of this LabelledStatement with argument « ».
return generate_labelled_evaluation ( generator , { } ) ;
}
// 14.13.4 Runtime Semantics: LabelledEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-labelledevaluation
// LabelledStatement : LabelIdentifier : LabelledItem
2023-01-08 19:23:00 -05:00
Bytecode : : CodeGenerationErrorOr < void > LabelledStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set ) const
2022-06-11 23:09:37 +01:00
{
// Convert the m_labelled_item NNRP to a reference early so we don't have to do it every single time we want to use it.
auto const & labelled_item = * m_labelled_item ;
// 1. Let label be the StringValue of LabelIdentifier.
// NOTE: Not necessary, this is m_label.
// 2. Let newLabelSet be the list-concatenation of labelSet and « label ».
// FIXME: Avoid copy here.
auto new_label_set = label_set ;
new_label_set . append ( m_label ) ;
// 3. Let stmtResult be LabelledEvaluation of LabelledItem with argument newLabelSet.
// NOTE: stmtResult will be in the accumulator after running the generated bytecode.
if ( is < IterationStatement > ( labelled_item ) ) {
auto const & iteration_statement = static_cast < IterationStatement const & > ( labelled_item ) ;
TRY ( iteration_statement . generate_labelled_evaluation ( generator , new_label_set ) ) ;
} else if ( is < SwitchStatement > ( labelled_item ) ) {
auto const & switch_statement = static_cast < SwitchStatement const & > ( labelled_item ) ;
TRY ( switch_statement . generate_labelled_evaluation ( generator , new_label_set ) ) ;
} else if ( is < LabelledStatement > ( labelled_item ) ) {
auto const & labelled_statement = static_cast < LabelledStatement const & > ( labelled_item ) ;
TRY ( labelled_statement . generate_labelled_evaluation ( generator , new_label_set ) ) ;
} else {
auto & labelled_break_block = generator . make_block ( ) ;
// NOTE: We do not need a continuable scope as `continue;` is not allowed outside of iteration statements, throwing a SyntaxError in the parser.
generator . begin_breakable_scope ( Bytecode : : Label { labelled_break_block } , new_label_set ) ;
TRY ( labelled_item . generate_bytecode ( generator ) ) ;
generator . end_breakable_scope ( ) ;
if ( ! generator . is_current_block_terminated ( ) ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { labelled_break_block } ,
{ } ) ;
}
generator . switch_to_basic_block ( labelled_break_block ) ;
}
// 4. If stmtResult.[[Type]] is break and SameValue(stmtResult.[[Target]], label) is true, then
// a. Set stmtResult to NormalCompletion(stmtResult.[[Value]]).
// NOTE: These steps are performed by making labelled break jump straight to the appropriate break block, which preserves the statement result's value in the accumulator.
// 5. Return Completion(stmtResult).
// NOTE: This is in the accumulator.
return { } ;
}
2023-01-08 19:23:00 -05:00
Bytecode : : CodeGenerationErrorOr < void > IterationStatement : : generate_labelled_evaluation ( Bytecode : : Generator & , Vector < DeprecatedFlyString > const & ) const
2022-06-11 23:09:37 +01:00
{
return Bytecode : : CodeGenerationError {
this ,
" Missing generate_labelled_evaluation() " sv ,
} ;
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > WhileStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
2023-01-08 19:23:00 -05:00
Bytecode : : CodeGenerationErrorOr < void > WhileStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set ) const
2021-06-04 12:07:38 +02:00
{
2021-06-09 06:49:58 +04:30
// test
// jump if_false (true) end (false) body
// body
// jump always (true) test
// end
auto & test_block = generator . make_block ( ) ;
auto & body_block = generator . make_block ( ) ;
2023-06-25 20:52:35 +01:00
auto & load_result_and_jump_to_end_block = generator . make_block ( ) ;
2021-06-09 06:49:58 +04:30
auto & end_block = generator . make_block ( ) ;
// Init result register
2021-06-08 22:17:00 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
auto result_reg = generator . allocate_register ( ) ;
2021-06-09 06:49:58 +04:30
// jump to the test block
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { test_block } ,
{ } ) ;
generator . switch_to_basic_block ( test_block ) ;
2023-06-25 20:52:35 +01:00
generator . emit < Bytecode : : Op : : Store > ( result_reg ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_test - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { body_block } ,
2023-06-25 20:52:35 +01:00
Bytecode : : Label { load_result_and_jump_to_end_block } ) ;
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( body_block ) ;
2022-06-11 23:09:37 +01:00
generator . begin_continuable_scope ( Bytecode : : Label { test_block } , label_set ) ;
generator . begin_breakable_scope ( Bytecode : : Label { end_block } , label_set ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
2022-03-14 02:13:33 +00:00
generator . end_breakable_scope ( ) ;
generator . end_continuable_scope ( ) ;
2021-06-09 19:57:18 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { test_block } ,
{ } ) ;
}
2022-02-12 19:54:08 +03:30
2023-06-25 20:52:35 +01:00
generator . switch_to_basic_block ( load_result_and_jump_to_end_block ) ;
2022-06-30 14:29:43 +01:00
generator . emit < Bytecode : : Op : : Load > ( result_reg ) ;
2023-06-25 20:52:35 +01:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
generator . switch_to_basic_block ( end_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 12:07:38 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > DoWhileStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
2023-01-08 19:23:00 -05:00
Bytecode : : CodeGenerationErrorOr < void > DoWhileStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set ) const
2021-06-04 12:20:44 +02:00
{
2021-06-09 06:49:58 +04:30
// jump always (true) body
// test
// jump if_false (true) end (false) body
// body
// jump always (true) test
// end
auto & test_block = generator . make_block ( ) ;
auto & body_block = generator . make_block ( ) ;
2023-06-25 20:52:35 +01:00
auto & load_result_and_jump_to_end_block = generator . make_block ( ) ;
2021-06-09 06:49:58 +04:30
auto & end_block = generator . make_block ( ) ;
// Init result register
2021-06-08 22:17:00 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
auto result_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( result_reg ) ;
2021-06-09 06:49:58 +04:30
// jump to the body block
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { body_block } ,
{ } ) ;
generator . switch_to_basic_block ( test_block ) ;
2023-06-25 20:52:35 +01:00
generator . emit < Bytecode : : Op : : Store > ( result_reg ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_test - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { body_block } ,
2023-06-25 20:52:35 +01:00
Bytecode : : Label { load_result_and_jump_to_end_block } ) ;
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( body_block ) ;
2022-06-11 23:09:37 +01:00
generator . begin_continuable_scope ( Bytecode : : Label { test_block } , label_set ) ;
generator . begin_breakable_scope ( Bytecode : : Label { end_block } , label_set ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
2022-03-14 02:13:33 +00:00
generator . end_breakable_scope ( ) ;
generator . end_continuable_scope ( ) ;
2021-06-09 19:57:18 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { test_block } ,
{ } ) ;
}
2022-02-12 19:54:08 +03:30
2023-06-25 20:52:35 +01:00
generator . switch_to_basic_block ( load_result_and_jump_to_end_block ) ;
2022-06-30 14:29:43 +01:00
generator . emit < Bytecode : : Op : : Load > ( result_reg ) ;
2023-06-25 20:52:35 +01:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
generator . switch_to_basic_block ( end_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 12:20:44 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ForStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
2023-01-08 19:23:00 -05:00
Bytecode : : CodeGenerationErrorOr < void > ForStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set ) const
2021-06-08 10:54:40 +01:00
{
2021-06-09 06:49:58 +04:30
// init
// jump always (true) test
// test
// jump if_true (true) body (false) end
// body
// jump always (true) update
// update
// jump always (true) test
// end
// If 'test' is missing, fuse the 'test' and 'body' basic blocks
// If 'update' is missing, fuse the 'body' and 'update' basic blocks
Bytecode : : BasicBlock * test_block_ptr { nullptr } ;
Bytecode : : BasicBlock * body_block_ptr { nullptr } ;
Bytecode : : BasicBlock * update_block_ptr { nullptr } ;
2023-06-25 20:52:35 +01:00
Bytecode : : BasicBlock * load_result_and_jump_to_end_block_ptr { nullptr } ;
2021-06-09 06:49:58 +04:30
auto & end_block = generator . make_block ( ) ;
2021-06-08 10:54:40 +01:00
2022-03-14 02:39:24 +00:00
bool has_lexical_environment = false ;
if ( m_init ) {
if ( m_init - > is_variable_declaration ( ) ) {
auto & variable_declaration = verify_cast < VariableDeclaration > ( * m_init ) ;
if ( variable_declaration . is_lexical_declaration ( ) ) {
has_lexical_environment = true ;
// FIXME: Is Block correct?
2023-06-16 16:34:47 +02:00
generator . begin_variable_scope ( ) ;
2022-03-14 02:39:24 +00:00
bool is_const = variable_declaration . is_constant_declaration ( ) ;
2023-02-27 22:13:37 +00:00
// NOTE: Nothing in the callback throws an exception.
MUST ( variable_declaration . for_each_bound_name ( [ & ] ( auto const & name ) {
2022-03-14 02:39:24 +00:00
auto index = generator . intern_identifier ( name ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( index , Bytecode : : Op : : EnvironmentMode : : Lexical , is_const ) ;
2023-02-27 22:13:37 +00:00
} ) ) ;
2022-03-14 02:39:24 +00:00
}
}
2022-02-12 19:54:08 +03:30
TRY ( m_init - > generate_bytecode ( generator ) ) ;
2022-03-14 02:39:24 +00:00
}
2021-06-07 20:58:36 -07:00
2021-06-09 06:49:58 +04:30
body_block_ptr = & generator . make_block ( ) ;
if ( m_test )
test_block_ptr = & generator . make_block ( ) ;
else
test_block_ptr = body_block_ptr ;
if ( m_update )
update_block_ptr = & generator . make_block ( ) ;
else
update_block_ptr = body_block_ptr ;
2021-06-08 22:17:00 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
auto result_reg = generator . allocate_register ( ) ;
2023-06-25 20:52:35 +01:00
if ( m_test & & m_update )
generator . emit < Bytecode : : Op : : Store > ( result_reg ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { * test_block_ptr } ,
{ } ) ;
2021-06-08 10:54:40 +01:00
if ( m_test ) {
2023-06-25 20:52:35 +01:00
load_result_and_jump_to_end_block_ptr = & generator . make_block ( ) ;
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( * test_block_ptr ) ;
2023-06-25 20:52:35 +01:00
if ( ! m_update )
generator . emit < Bytecode : : Op : : Store > ( result_reg ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_test - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { * body_block_ptr } ,
2023-06-25 20:52:35 +01:00
Bytecode : : Label { * load_result_and_jump_to_end_block_ptr } ) ;
2021-06-08 10:54:40 +01:00
}
2021-06-07 20:58:36 -07:00
2023-06-15 19:13:00 +02:00
if ( m_update ) {
generator . switch_to_basic_block ( * update_block_ptr ) ;
2023-06-25 20:52:35 +01:00
if ( m_test )
generator . emit < Bytecode : : Op : : Store > ( result_reg ) ;
2023-06-15 19:13:00 +02:00
TRY ( m_update - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { * test_block_ptr } ,
{ } ) ;
}
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( * body_block_ptr ) ;
2023-06-15 19:13:00 +02:00
generator . begin_continuable_scope ( Bytecode : : Label { m_update ? * update_block_ptr : * test_block_ptr } , label_set ) ;
2022-07-17 19:22:18 +01:00
generator . begin_breakable_scope ( Bytecode : : Label { end_block } , label_set ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
2022-07-17 19:22:18 +01:00
generator . end_breakable_scope ( ) ;
2021-06-08 10:54:40 +01:00
generator . end_continuable_scope ( ) ;
2021-06-09 06:49:58 +04:30
2021-06-09 19:57:18 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
if ( m_update ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { * update_block_ptr } ,
{ } ) ;
2023-06-15 19:13:00 +02:00
} else {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { * test_block_ptr } ,
{ } ) ;
2021-06-09 19:57:18 +02:00
}
2021-06-09 06:49:58 +04:30
}
2022-02-12 19:54:08 +03:30
2023-06-25 20:52:35 +01:00
if ( load_result_and_jump_to_end_block_ptr ) {
generator . switch_to_basic_block ( * load_result_and_jump_to_end_block_ptr ) ;
generator . emit < Bytecode : : Op : : Load > ( result_reg ) ;
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
}
2022-06-30 15:55:57 +01:00
generator . switch_to_basic_block ( end_block ) ;
2022-03-15 01:44:32 +00:00
if ( has_lexical_environment )
generator . end_variable_scope ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 10:54:40 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ObjectExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 20:30:23 +02:00
{
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : NewObject > ( ) ;
2021-06-11 19:40:48 +03:00
if ( m_properties . is_empty ( ) )
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 20:30:23 +02:00
2021-06-11 19:40:48 +03:00
auto object_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( object_reg ) ;
2023-06-16 10:25:05 +02:00
generator . push_home_object ( object_reg ) ;
2021-06-11 19:40:48 +03:00
for ( auto & property : m_properties ) {
2022-03-31 00:59:58 +04:30
Bytecode : : Op : : PropertyKind property_kind ;
2023-03-06 14:17:01 +01:00
switch ( property - > type ( ) ) {
2022-03-31 00:59:58 +04:30
case ObjectProperty : : Type : : KeyValue :
property_kind = Bytecode : : Op : : PropertyKind : : KeyValue ;
break ;
case ObjectProperty : : Type : : Getter :
property_kind = Bytecode : : Op : : PropertyKind : : Getter ;
break ;
case ObjectProperty : : Type : : Setter :
property_kind = Bytecode : : Op : : PropertyKind : : Setter ;
break ;
case ObjectProperty : : Type : : Spread :
property_kind = Bytecode : : Op : : PropertyKind : : Spread ;
break ;
case ObjectProperty : : Type : : ProtoSetter :
property_kind = Bytecode : : Op : : PropertyKind : : ProtoSetter ;
break ;
}
2021-06-11 19:40:48 +03:00
2023-03-06 14:17:01 +01:00
if ( is < StringLiteral > ( property - > key ( ) ) ) {
auto & string_literal = static_cast < StringLiteral const & > ( property - > key ( ) ) ;
2021-10-24 15:34:30 +02:00
Bytecode : : IdentifierTableIndex key_name = generator . intern_identifier ( string_literal . value ( ) ) ;
2021-06-11 19:40:48 +03:00
2023-06-25 19:25:38 +02:00
if ( property_kind = = Bytecode : : Op : : PropertyKind : : ProtoSetter ) {
2023-03-06 14:17:01 +01:00
TRY ( property - > value ( ) . generate_bytecode ( generator ) ) ;
2023-06-25 19:25:38 +02:00
} else if ( property_kind ! = Bytecode : : Op : : PropertyKind : : Spread ) {
DeprecatedFlyString name = string_literal . value ( ) ;
TRY ( generator . emit_named_evaluation_if_anonymous_function ( property - > value ( ) , name ) ) ;
}
2022-03-31 00:59:58 +04:30
generator . emit < Bytecode : : Op : : PutById > ( object_reg , key_name , property_kind ) ;
2021-06-11 19:40:48 +03:00
} else {
2023-03-06 14:17:01 +01:00
TRY ( property - > key ( ) . generate_bytecode ( generator ) ) ;
2021-06-11 19:40:48 +03:00
auto property_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( property_reg ) ;
2022-03-31 00:59:58 +04:30
if ( property_kind ! = Bytecode : : Op : : PropertyKind : : Spread )
2023-03-06 14:17:01 +01:00
TRY ( property - > value ( ) . generate_bytecode ( generator ) ) ;
2022-03-31 00:59:58 +04:30
generator . emit < Bytecode : : Op : : PutByValue > ( object_reg , property_reg , property_kind ) ;
2021-06-11 19:40:48 +03:00
}
}
generator . emit < Bytecode : : Op : : Load > ( object_reg ) ;
2023-06-16 10:25:05 +02:00
generator . pop_home_object ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 20:30:23 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ArrayExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 23:06:52 +02:00
{
2022-09-09 15:23:02 +02:00
if ( m_elements . is_empty ( ) ) {
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
return { } ;
2022-03-14 14:48:42 +00:00
}
2021-06-08 23:06:52 +02:00
2022-09-09 15:23:02 +02:00
auto first_spread = find_if ( m_elements . begin ( ) , m_elements . end ( ) , [ ] ( auto el ) { return el & & is < SpreadExpression > ( * el ) ; } ) ;
Bytecode : : Register args_start_reg { 0 } ;
for ( auto it = m_elements . begin ( ) ; it ! = first_spread ; + + it ) {
auto reg = generator . allocate_register ( ) ;
if ( args_start_reg . index ( ) = = 0 )
args_start_reg = reg ;
}
u32 i = 0 ;
for ( auto it = m_elements . begin ( ) ; it ! = first_spread ; + + it , + + i ) {
Bytecode : : Register reg { args_start_reg . index ( ) + i } ;
if ( ! * it )
2021-06-09 04:43:13 +01:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value { } ) ;
2022-09-09 15:23:02 +02:00
else {
TRY ( ( * it ) - > generate_bytecode ( generator ) ) ;
2021-06-08 23:06:52 +02:00
}
2022-09-09 15:23:02 +02:00
generator . emit < Bytecode : : Op : : Store > ( reg ) ;
2021-06-08 23:06:52 +02:00
}
2022-09-09 15:23:02 +02:00
if ( first_spread . index ( ) ! = 0 )
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2u , AK : : Array { args_start_reg , Bytecode : : Register { args_start_reg . index ( ) + static_cast < u32 > ( first_spread . index ( ) - 1 ) } } ) ;
else
2022-03-14 14:48:42 +00:00
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
2022-09-09 15:23:02 +02:00
if ( first_spread ! = m_elements . end ( ) ) {
auto array_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( array_reg ) ;
for ( auto it = first_spread ; it ! = m_elements . end ( ) ; + + it ) {
if ( ! * it ) {
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value { } ) ;
generator . emit < Bytecode : : Op : : Append > ( array_reg , false ) ;
} else {
TRY ( ( * it ) - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : Append > ( array_reg , * it & & is < SpreadExpression > ( * * it ) ) ;
}
}
generator . emit < Bytecode : : Op : : Load > ( array_reg ) ;
2022-03-14 14:48:42 +00:00
}
2022-09-09 15:23:02 +02:00
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 23:06:52 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > MemberExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 21:03:53 +02:00
{
2022-02-12 19:54:08 +03:30
return generator . emit_load_from_reference ( * this ) ;
2021-06-04 21:03:53 +02:00
}
2022-02-12 19:48:45 +03:30
Bytecode : : CodeGenerationErrorOr < void > FunctionDeclaration : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-05 15:15:30 +02:00
{
2022-02-12 19:48:45 +03:30
if ( m_is_hoisted ) {
auto index = generator . intern_identifier ( name ( ) ) ;
generator . emit < Bytecode : : Op : : GetVariable > ( index ) ;
2022-03-13 12:43:45 +03:30
generator . emit < Bytecode : : Op : : SetVariable > ( index , Bytecode : : Op : : SetVariable : : InitializationMode : : Set , Bytecode : : Op : : EnvironmentMode : : Var ) ;
2022-02-12 19:48:45 +03:30
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-05 15:15:30 +02:00
}
2023-06-23 14:27:42 +02:00
Bytecode : : CodeGenerationErrorOr < void > FunctionExpression : : generate_bytecode_with_lhs_name ( Bytecode : : Generator & generator , Optional < DeprecatedFlyString const & > lhs_name ) const
2021-06-11 10:46:46 +02:00
{
2022-06-11 23:24:55 +01:00
bool has_name = ! name ( ) . is_empty ( ) ;
Optional < Bytecode : : IdentifierTableIndex > name_identifier ;
if ( has_name ) {
2023-06-16 16:34:47 +02:00
generator . begin_variable_scope ( ) ;
2022-06-11 23:24:55 +01:00
name_identifier = generator . intern_identifier ( name ( ) ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( * name_identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , true ) ;
}
2023-06-23 14:27:42 +02:00
generator . emit_new_function ( * this , lhs_name ) ;
2022-06-11 23:24:55 +01:00
if ( has_name ) {
generator . emit < Bytecode : : Op : : SetVariable > ( * name_identifier , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , Bytecode : : Op : : EnvironmentMode : : Lexical ) ;
generator . end_variable_scope ( ) ;
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-11 10:46:46 +02:00
}
2023-06-23 14:27:42 +02:00
Bytecode : : CodeGenerationErrorOr < void > FunctionExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
return generate_bytecode_with_lhs_name ( generator , { } ) ;
}
2023-06-24 20:29:30 +02:00
static Bytecode : : CodeGenerationErrorOr < void > generate_object_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode initialization_mode , Bytecode : : Register const & value_reg , bool create_variables )
2021-06-13 12:24:55 -07:00
{
2023-06-25 08:50:07 +02:00
generator . emit < Bytecode : : Op : : ThrowIfNullish > ( ) ;
2021-06-13 15:30:32 -07:00
Vector < Bytecode : : Register > excluded_property_names ;
auto has_rest = false ;
if ( pattern . entries . size ( ) > 0 )
has_rest = pattern . entries [ pattern . entries . size ( ) - 1 ] . is_rest ;
2021-06-13 12:24:55 -07:00
for ( auto & [ name , alias , initializer , is_rest ] : pattern . entries ) {
2021-06-13 15:30:32 -07:00
if ( is_rest ) {
2023-02-19 22:07:52 +01:00
VERIFY ( name . has < NonnullRefPtr < Identifier const > > ( ) ) ;
2021-06-13 15:30:32 -07:00
VERIFY ( alias . has < Empty > ( ) ) ;
VERIFY ( ! initializer ) ;
2023-02-19 22:07:52 +01:00
auto identifier = name . get < NonnullRefPtr < Identifier const > > ( ) - > string ( ) ;
2021-10-24 15:34:30 +02:00
auto interned_identifier = generator . intern_identifier ( identifier ) ;
2021-06-13 15:30:32 -07:00
generator . emit_with_extra_register_slots < Bytecode : : Op : : CopyObjectExcludingProperties > ( excluded_property_names . size ( ) , value_reg , excluded_property_names ) ;
2023-06-24 20:29:30 +02:00
if ( create_variables )
generator . emit < Bytecode : : Op : : CreateVariable > ( interned_identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
2022-02-12 19:54:08 +03:30
generator . emit < Bytecode : : Op : : SetVariable > ( interned_identifier , initialization_mode ) ;
2021-06-13 15:30:32 -07:00
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-13 15:30:32 -07:00
}
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
Bytecode : : StringTableIndex name_index ;
2021-06-13 12:24:55 -07:00
2023-02-19 22:07:52 +01:00
if ( name . has < NonnullRefPtr < Identifier const > > ( ) ) {
auto identifier = name . get < NonnullRefPtr < Identifier const > > ( ) - > string ( ) ;
2021-06-13 13:40:48 -07:00
name_index = generator . intern_string ( identifier ) ;
2021-06-13 15:30:32 -07:00
if ( has_rest ) {
auto excluded_name_reg = generator . allocate_register ( ) ;
excluded_property_names . append ( excluded_name_reg ) ;
generator . emit < Bytecode : : Op : : NewString > ( name_index ) ;
generator . emit < Bytecode : : Op : : Store > ( excluded_name_reg ) ;
}
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : Load > ( value_reg ) ;
2021-10-24 15:34:30 +02:00
generator . emit < Bytecode : : Op : : GetById > ( generator . intern_identifier ( identifier ) ) ;
2021-06-13 13:40:48 -07:00
} else {
2023-02-19 22:07:52 +01:00
auto expression = name . get < NonnullRefPtr < Expression const > > ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( expression - > generate_bytecode ( generator ) ) ;
2021-06-13 15:30:32 -07:00
if ( has_rest ) {
auto excluded_name_reg = generator . allocate_register ( ) ;
excluded_property_names . append ( excluded_name_reg ) ;
generator . emit < Bytecode : : Op : : Store > ( excluded_name_reg ) ;
}
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : GetByValue > ( value_reg ) ;
}
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
if ( initializer ) {
auto & if_undefined_block = generator . make_block ( ) ;
auto & if_not_undefined_block = generator . make_block ( ) ;
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : JumpUndefined > ( ) . set_targets (
Bytecode : : Label { if_undefined_block } ,
Bytecode : : Label { if_not_undefined_block } ) ;
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
generator . switch_to_basic_block ( if_undefined_block ) ;
2023-06-27 14:41:09 +02:00
if ( auto const * alias_identifier = alias . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
TRY ( generator . emit_named_evaluation_if_anonymous_function ( * initializer , ( * alias_identifier ) - > string ( ) ) ) ;
} else if ( auto const * lhs = name . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
2023-06-23 14:27:42 +02:00
TRY ( generator . emit_named_evaluation_if_anonymous_function ( * initializer , ( * lhs ) - > string ( ) ) ) ;
} else {
TRY ( initializer - > generate_bytecode ( generator ) ) ;
}
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { if_not_undefined_block } ,
{ } ) ;
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
generator . switch_to_basic_block ( if_not_undefined_block ) ;
}
2021-06-13 12:24:55 -07:00
2023-02-19 22:07:52 +01:00
if ( alias . has < NonnullRefPtr < BindingPattern const > > ( ) ) {
auto & binding_pattern = * alias . get < NonnullRefPtr < BindingPattern const > > ( ) ;
2021-06-13 13:40:48 -07:00
auto nested_value_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( nested_value_reg ) ;
2023-06-24 20:29:30 +02:00
TRY ( generate_binding_pattern_bytecode ( generator , binding_pattern , initialization_mode , nested_value_reg , create_variables ) ) ;
2021-06-13 13:40:48 -07:00
} else if ( alias . has < Empty > ( ) ) {
2023-02-19 22:07:52 +01:00
if ( name . has < NonnullRefPtr < Expression const > > ( ) ) {
2021-06-13 13:40:48 -07:00
// This needs some sort of SetVariableByValue opcode, as it's a runtime binding
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
2023-02-19 22:07:52 +01:00
name . get < NonnullRefPtr < Expression const > > ( ) . ptr ( ) ,
2022-02-12 19:54:08 +03:30
" Unimplemented name/alias pair: Empty/Expression " sv ,
} ;
2021-06-13 12:24:55 -07:00
}
2021-06-13 13:40:48 -07:00
2023-02-19 22:07:52 +01:00
auto & identifier = name . get < NonnullRefPtr < Identifier const > > ( ) - > string ( ) ;
2023-06-24 20:29:30 +02:00
auto identifier_ref = generator . intern_identifier ( identifier ) ;
if ( create_variables )
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier_ref , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( identifier_ref , initialization_mode ) ;
2023-06-25 16:24:05 +02:00
} else if ( alias . has < NonnullRefPtr < MemberExpression const > > ( ) ) {
TRY ( generator . emit_store_to_reference ( alias . get < NonnullRefPtr < MemberExpression const > > ( ) ) ) ;
2021-06-13 12:24:55 -07:00
} else {
2023-02-19 22:07:52 +01:00
auto & identifier = alias . get < NonnullRefPtr < Identifier const > > ( ) - > string ( ) ;
2023-06-24 20:29:30 +02:00
auto identifier_ref = generator . intern_identifier ( identifier ) ;
if ( create_variables )
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier_ref , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( identifier_ref , initialization_mode ) ;
2021-06-13 13:40:48 -07:00
}
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-13 13:40:48 -07:00
}
2023-06-24 20:29:30 +02:00
static Bytecode : : CodeGenerationErrorOr < void > generate_array_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode initialization_mode , Bytecode : : Register const & value_reg , bool create_variables )
2021-06-13 13:40:48 -07:00
{
/*
* Consider the following destructuring assignment :
*
* let [ a , b , c , d , e ] = o ;
*
* It would be fairly trivial to just loop through this iterator , getting the value
* at each step and assigning them to the binding sequentially . However , this is not
* correct : once an iterator is exhausted , it must not be called again . This complicates
* the bytecode . In order to accomplish this , we do the following :
*
* - Reserve a special boolean register which holds ' true ' if the iterator is exhausted ,
* and false otherwise
* - When we are retrieving the value which should be bound , we first check this register .
* If it is ' true ' , we load undefined into the accumulator . Otherwise , we grab the next
* value from the iterator and store it into the accumulator .
*
* Note that the is_exhausted register does not need to be loaded with false because the
* first IteratorNext bytecode is _not_ proceeded by an exhausted check , as it is
* unnecessary .
*/
auto is_iterator_exhausted_register = generator . allocate_register ( ) ;
2023-06-26 17:21:12 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value ( false ) ) ;
generator . emit < Bytecode : : Op : : Store > ( is_iterator_exhausted_register ) ;
2021-06-13 13:40:48 -07:00
auto iterator_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Load > ( value_reg ) ;
generator . emit < Bytecode : : Op : : GetIterator > ( ) ;
generator . emit < Bytecode : : Op : : Store > ( iterator_reg ) ;
bool first = true ;
auto temp_iterator_result_reg = generator . allocate_register ( ) ;
2021-06-13 14:06:26 -07:00
auto assign_accumulator_to_alias = [ & ] ( auto & alias ) {
2022-02-12 19:54:08 +03:30
return alias . visit (
[ & ] ( Empty ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-06-13 14:06:26 -07:00
// This element is an elision
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-13 14:06:26 -07:00
} ,
2023-02-19 22:07:52 +01:00
[ & ] ( NonnullRefPtr < Identifier const > const & identifier ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-10-24 15:34:30 +02:00
auto interned_index = generator . intern_identifier ( identifier - > string ( ) ) ;
2023-06-24 20:29:30 +02:00
if ( create_variables )
generator . emit < Bytecode : : Op : : CreateVariable > ( interned_index , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
2022-02-12 19:54:08 +03:30
generator . emit < Bytecode : : Op : : SetVariable > ( interned_index , initialization_mode ) ;
return { } ;
2021-06-13 14:06:26 -07:00
} ,
2023-02-19 22:07:52 +01:00
[ & ] ( NonnullRefPtr < BindingPattern const > const & pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-06-13 14:06:26 -07:00
// Store the accumulator value in a permanent register
auto target_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( target_reg ) ;
2023-06-24 20:29:30 +02:00
return generate_binding_pattern_bytecode ( generator , pattern , initialization_mode , target_reg , create_variables ) ;
2021-09-18 01:11:32 +02:00
} ,
2023-02-19 22:07:52 +01:00
[ & ] ( NonnullRefPtr < MemberExpression const > const & expr ) - > Bytecode : : CodeGenerationErrorOr < void > {
2022-03-31 03:09:08 +04:30
return generator . emit_store_to_reference ( * expr ) ;
2021-06-13 14:06:26 -07:00
} ) ;
} ;
2021-06-13 13:40:48 -07:00
for ( auto & [ name , alias , initializer , is_rest ] : pattern . entries ) {
VERIFY ( name . has < Empty > ( ) ) ;
2021-06-13 14:06:26 -07:00
if ( is_rest ) {
2022-07-17 19:25:23 +01:00
VERIFY ( ! initializer ) ;
2021-06-13 14:06:26 -07:00
if ( first ) {
// The iterator has not been called, and is thus known to be not exhausted
generator . emit < Bytecode : : Op : : Load > ( iterator_reg ) ;
generator . emit < Bytecode : : Op : : IteratorToArray > ( ) ;
} else {
auto & if_exhausted_block = generator . make_block ( ) ;
auto & if_not_exhausted_block = generator . make_block ( ) ;
auto & continuation_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Load > ( is_iterator_exhausted_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { if_exhausted_block } ,
Bytecode : : Label { if_not_exhausted_block } ) ;
generator . switch_to_basic_block ( if_exhausted_block ) ;
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { continuation_block } ,
{ } ) ;
generator . switch_to_basic_block ( if_not_exhausted_block ) ;
generator . emit < Bytecode : : Op : : Load > ( iterator_reg ) ;
generator . emit < Bytecode : : Op : : IteratorToArray > ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { continuation_block } ,
{ } ) ;
generator . switch_to_basic_block ( continuation_block ) ;
}
2022-02-12 19:54:08 +03:30
return assign_accumulator_to_alias ( alias ) ;
2021-06-13 14:06:26 -07:00
}
2021-06-13 13:40:48 -07:00
// In the first iteration of the loop, a few things are true which can save
// us some bytecode:
// - the iterator result is still in the accumulator, so we can avoid a load
// - the iterator is not yet exhausted, which can save us a jump and some
// creation
auto & iterator_is_exhausted_block = generator . make_block ( ) ;
if ( ! first ) {
auto & iterator_is_not_exhausted_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Load > ( is_iterator_exhausted_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { iterator_is_exhausted_block } ,
Bytecode : : Label { iterator_is_not_exhausted_block } ) ;
generator . switch_to_basic_block ( iterator_is_not_exhausted_block ) ;
generator . emit < Bytecode : : Op : : Load > ( iterator_reg ) ;
2021-06-13 12:24:55 -07:00
}
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : IteratorNext > ( ) ;
generator . emit < Bytecode : : Op : : Store > ( temp_iterator_result_reg ) ;
generator . emit < Bytecode : : Op : : IteratorResultDone > ( ) ;
generator . emit < Bytecode : : Op : : Store > ( is_iterator_exhausted_register ) ;
// We still have to check for exhaustion here. If the iterator is exhausted,
// we need to bail before trying to get the value
auto & no_bail_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { iterator_is_exhausted_block } ,
Bytecode : : Label { no_bail_block } ) ;
generator . switch_to_basic_block ( no_bail_block ) ;
// Get the next value in the iterator
generator . emit < Bytecode : : Op : : Load > ( temp_iterator_result_reg ) ;
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
auto & create_binding_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { create_binding_block } ,
{ } ) ;
// The iterator is exhausted, so we just load undefined and continue binding
generator . switch_to_basic_block ( iterator_is_exhausted_block ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { create_binding_block } ,
{ } ) ;
// Create the actual binding. The value which this entry must bind is now in the
// accumulator. We can proceed, processing the alias as a nested destructuring
// pattern if necessary.
generator . switch_to_basic_block ( create_binding_block ) ;
2022-07-17 19:25:23 +01:00
if ( initializer ) {
auto & value_is_undefined_block = generator . make_block ( ) ;
auto & value_is_not_undefined_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpUndefined > ( ) . set_targets (
Bytecode : : Label { value_is_undefined_block } ,
Bytecode : : Label { value_is_not_undefined_block } ) ;
generator . switch_to_basic_block ( value_is_undefined_block ) ;
2023-06-23 14:27:42 +02:00
2023-06-25 11:11:36 +02:00
if ( auto const * alias_identifier = alias . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
TRY ( generator . emit_named_evaluation_if_anonymous_function ( * initializer , ( * alias_identifier ) - > string ( ) ) ) ;
} else if ( auto const * name_identifier = name . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
TRY ( generator . emit_named_evaluation_if_anonymous_function ( * initializer , ( * name_identifier ) - > string ( ) ) ) ;
2023-06-23 14:27:42 +02:00
} else {
TRY ( initializer - > generate_bytecode ( generator ) ) ;
}
2022-07-17 19:25:23 +01:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { value_is_not_undefined_block } ) ;
generator . switch_to_basic_block ( value_is_not_undefined_block ) ;
}
2022-02-12 19:54:08 +03:30
TRY ( assign_accumulator_to_alias ( alias ) ) ;
2021-06-13 13:40:48 -07:00
first = false ;
}
2022-02-12 19:54:08 +03:30
2023-06-26 17:21:12 +02:00
auto & done_block = generator . make_block ( ) ;
auto & not_done_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Load > ( is_iterator_exhausted_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { done_block } ,
Bytecode : : Label { not_done_block } ) ;
generator . switch_to_basic_block ( not_done_block ) ;
generator . emit < Bytecode : : Op : : Load > ( iterator_reg ) ;
generator . emit < Bytecode : : Op : : IteratorClose > ( Completion : : Type : : Normal , Optional < Value > { } ) ;
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { done_block } ) ;
generator . switch_to_basic_block ( done_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-13 13:40:48 -07:00
}
2023-06-24 20:29:30 +02:00
static Bytecode : : CodeGenerationErrorOr < void > generate_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode initialization_mode , Bytecode : : Register const & value_reg , bool create_variables )
2021-06-13 13:40:48 -07:00
{
2022-02-12 19:54:08 +03:30
if ( pattern . kind = = BindingPattern : : Kind : : Object )
2023-06-24 20:29:30 +02:00
return generate_object_binding_pattern_bytecode ( generator , pattern , initialization_mode , value_reg , create_variables ) ;
2022-02-12 19:54:08 +03:30
2023-06-24 20:29:30 +02:00
return generate_array_binding_pattern_bytecode ( generator , pattern , initialization_mode , value_reg , create_variables ) ;
2022-02-12 19:54:08 +03:30
}
2021-06-13 12:24:55 -07:00
2022-03-18 20:18:19 +03:30
static Bytecode : : CodeGenerationErrorOr < void > assign_accumulator_to_variable_declarator ( Bytecode : : Generator & generator , VariableDeclarator const & declarator , VariableDeclaration const & declaration )
{
auto initialization_mode = declaration . is_lexical_declaration ( ) ? Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize : Bytecode : : Op : : SetVariable : : InitializationMode : : Set ;
return declarator . target ( ) . visit (
2023-02-19 22:07:52 +01:00
[ & ] ( NonnullRefPtr < Identifier const > const & id ) - > Bytecode : : CodeGenerationErrorOr < void > {
2023-05-13 13:37:12 +02:00
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( id - > string ( ) ) , initialization_mode ) ;
2022-03-18 20:18:19 +03:30
return { } ;
} ,
2023-02-19 22:07:52 +01:00
[ & ] ( NonnullRefPtr < BindingPattern const > const & pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
2022-03-18 20:18:19 +03:30
auto value_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( value_register ) ;
2023-06-24 20:29:30 +02:00
return generate_binding_pattern_bytecode ( generator , pattern , initialization_mode , value_register , false ) ;
2022-03-18 20:18:19 +03:30
} ) ;
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > VariableDeclaration : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-10 00:29:17 +02:00
{
2021-06-10 22:12:21 +02:00
for ( auto & declarator : m_declarations ) {
2023-06-17 15:16:30 +02:00
if ( declarator - > init ( ) ) {
2023-06-23 14:27:42 +02:00
if ( auto const * lhs = declarator - > target ( ) . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
TRY ( generator . emit_named_evaluation_if_anonymous_function ( * declarator - > init ( ) , ( * lhs ) - > string ( ) ) ) ;
} else {
TRY ( declarator - > init ( ) - > generate_bytecode ( generator ) ) ;
}
2023-06-17 15:16:30 +02:00
TRY ( assign_accumulator_to_variable_declarator ( generator , declarator , * this ) ) ;
} else if ( m_declaration_kind ! = DeclarationKind : : Var ) {
2021-06-10 22:12:21 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2023-06-17 15:16:30 +02:00
TRY ( assign_accumulator_to_variable_declarator ( generator , declarator , * this ) ) ;
}
2021-06-10 22:12:21 +02:00
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-10 00:29:17 +02:00
}
2023-06-17 14:50:23 +01:00
static Bytecode : : CodeGenerationErrorOr < void > get_base_and_value_from_member_expression ( Bytecode : : Generator & generator , MemberExpression const & member_expression , Bytecode : : Register this_reg )
{
// https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
if ( is < SuperExpression > ( member_expression . object ( ) ) ) {
// 1. Let env be GetThisEnvironment().
// 2. Let actualThis be ? env.GetThisBinding().
generator . emit < Bytecode : : Op : : ResolveThisBinding > ( ) ;
generator . emit < Bytecode : : Op : : Store > ( this_reg ) ;
Optional < Bytecode : : Register > computed_property_value_register ;
if ( member_expression . is_computed ( ) ) {
// SuperProperty : super [ Expression ]
// 3. Let propertyNameReference be ? Evaluation of Expression.
// 4. Let propertyNameValue be ? GetValue(propertyNameReference).
TRY ( member_expression . property ( ) . generate_bytecode ( generator ) ) ;
computed_property_value_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( * computed_property_value_register ) ;
}
// 5/7. Return ? MakeSuperPropertyReference(actualThis, propertyKey, strict).
// https://tc39.es/ecma262/#sec-makesuperpropertyreference
// 1. Let env be GetThisEnvironment().
// 2. Assert: env.HasSuperBinding() is true.
// 3. Let baseValue be ? env.GetSuperBase().
generator . emit < Bytecode : : Op : : ResolveSuperBase > ( ) ;
// 4. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }.
if ( computed_property_value_register . has_value ( ) ) {
// 5. Let propertyKey be ? ToPropertyKey(propertyNameValue).
// FIXME: This does ToPropertyKey out of order, which is observable by Symbol.toPrimitive!
2023-06-17 18:42:32 +01:00
auto super_base_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( super_base_register ) ;
generator . emit < Bytecode : : Op : : Load > ( * computed_property_value_register ) ;
generator . emit < Bytecode : : Op : : GetByValue > ( super_base_register ) ;
2023-06-17 14:50:23 +01:00
} else {
// 3. Let propertyKey be StringValue of IdentifierName.
auto identifier_table_ref = generator . intern_identifier ( verify_cast < Identifier > ( member_expression . property ( ) ) . string ( ) ) ;
generator . emit < Bytecode : : Op : : GetById > ( identifier_table_ref ) ;
}
} else {
TRY ( member_expression . object ( ) . generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : Store > ( this_reg ) ;
if ( member_expression . is_computed ( ) ) {
TRY ( member_expression . property ( ) . generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : GetByValue > ( this_reg ) ;
2023-06-23 17:09:32 +02:00
} else if ( is < PrivateIdentifier > ( member_expression . property ( ) ) ) {
generator . emit < Bytecode : : Op : : GetPrivateById > ( generator . intern_identifier ( verify_cast < PrivateIdentifier > ( member_expression . property ( ) ) . string ( ) ) ) ;
2023-06-17 14:50:23 +01:00
} else {
2023-06-23 17:09:32 +02:00
generator . emit < Bytecode : : Op : : GetById > ( generator . intern_identifier ( verify_cast < Identifier > ( member_expression . property ( ) ) . string ( ) ) ) ;
2023-06-17 14:50:23 +01:00
}
}
return { } ;
}
static Bytecode : : CodeGenerationErrorOr < void > generate_optional_chain ( Bytecode : : Generator & generator , OptionalChain const & optional_chain , Bytecode : : Register current_value_register , Bytecode : : Register current_base_register ) ;
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > CallExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-05 15:15:30 +02:00
{
2021-06-07 20:58:36 -07:00
auto callee_reg = generator . allocate_register ( ) ;
2021-06-05 15:15:30 +02:00
auto this_reg = generator . allocate_register ( ) ;
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Store > ( this_reg ) ;
2021-06-05 15:15:30 +02:00
2021-06-11 01:36:10 +04:30
if ( is < NewExpression > ( this ) ) {
2022-02-12 19:54:08 +03:30
TRY ( m_callee - > generate_bytecode ( generator ) ) ;
2021-06-11 01:36:10 +04:30
generator . emit < Bytecode : : Op : : Store > ( callee_reg ) ;
} else if ( is < MemberExpression > ( * m_callee ) ) {
2022-04-01 20:58:27 +03:00
auto & member_expression = static_cast < MemberExpression const & > ( * m_callee ) ;
2023-06-17 14:50:23 +01:00
TRY ( get_base_and_value_from_member_expression ( generator , member_expression , this_reg ) ) ;
2022-02-12 19:54:08 +03:30
generator . emit < Bytecode : : Op : : Store > ( callee_reg ) ;
2023-06-17 14:50:23 +01:00
} else if ( is < OptionalChain > ( * m_callee ) ) {
auto & optional_chain = static_cast < OptionalChain const & > ( * m_callee ) ;
TRY ( generate_optional_chain ( generator , optional_chain , callee_reg , this_reg ) ) ;
2021-06-11 01:36:10 +04:30
} else {
// FIXME: this = global object in sloppy mode.
2022-02-12 19:54:08 +03:30
TRY ( m_callee - > generate_bytecode ( generator ) ) ;
2021-06-11 01:36:10 +04:30
generator . emit < Bytecode : : Op : : Store > ( callee_reg ) ;
}
2022-11-26 19:51:50 +01:00
TRY ( arguments_to_array_for_call ( generator , arguments ( ) ) ) ;
2021-06-10 23:01:49 +02:00
Bytecode : : Op : : Call : : CallType call_type ;
if ( is < NewExpression > ( * this ) ) {
call_type = Bytecode : : Op : : Call : : CallType : : Construct ;
2023-06-15 13:16:01 +02:00
} else if ( m_callee - > is_identifier ( ) & & static_cast < Identifier const & > ( * m_callee ) . string ( ) = = " eval " sv ) {
call_type = Bytecode : : Op : : Call : : CallType : : DirectEval ;
2021-06-10 23:01:49 +02:00
} else {
call_type = Bytecode : : Op : : Call : : CallType : : Call ;
}
2022-10-01 01:36:06 +02:00
Optional < Bytecode : : StringTableIndex > expression_string_index ;
if ( auto expression_string = this - > expression_string ( ) ; expression_string . has_value ( ) )
expression_string_index = generator . intern_string ( expression_string . release_value ( ) ) ;
generator . emit < Bytecode : : Op : : Call > ( call_type , callee_reg , this_reg , expression_string_index ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-05 15:15:30 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ReturnStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-05 15:53:36 +02:00
{
2021-06-08 16:29:21 -07:00
if ( m_argument )
2022-02-12 19:54:08 +03:30
TRY ( m_argument - > generate_bytecode ( generator ) ) ;
2022-06-11 23:13:02 +01:00
else
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2021-06-11 01:38:30 +04:30
2022-03-13 11:51:02 +03:30
if ( generator . is_in_generator_or_async_function ( ) ) {
generator . perform_needed_unwinds < Bytecode : : Op : : Yield > ( ) ;
2021-06-11 01:38:30 +04:30
generator . emit < Bytecode : : Op : : Yield > ( nullptr ) ;
2022-03-13 11:51:02 +03:30
} else {
generator . perform_needed_unwinds < Bytecode : : Op : : Return > ( ) ;
2021-06-11 01:38:30 +04:30
generator . emit < Bytecode : : Op : : Return > ( ) ;
2022-03-13 11:51:02 +03:30
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-11 01:38:30 +04:30
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > YieldExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-11 01:38:30 +04:30
{
VERIFY ( generator . is_in_generator_function ( ) ) ;
2022-11-25 23:14:08 +00:00
auto received_completion_register = generator . allocate_register ( ) ;
auto received_completion_type_register = generator . allocate_register ( ) ;
auto received_completion_value_register = generator . allocate_register ( ) ;
auto type_identifier = generator . intern_identifier ( " type " ) ;
auto value_identifier = generator . intern_identifier ( " value " ) ;
auto get_received_completion_type_and_value = [ & ] ( ) {
// The accumulator is set to an object, for example: { "type": 1 (normal), value: 1337 }
generator . emit < Bytecode : : Op : : Store > ( received_completion_register ) ;
generator . emit < Bytecode : : Op : : GetById > ( type_identifier ) ;
generator . emit < Bytecode : : Op : : Store > ( received_completion_type_register ) ;
generator . emit < Bytecode : : Op : : Load > ( received_completion_register ) ;
generator . emit < Bytecode : : Op : : GetById > ( value_identifier ) ;
generator . emit < Bytecode : : Op : : Store > ( received_completion_value_register ) ;
} ;
2022-02-12 19:54:08 +03:30
if ( m_is_yield_from ) {
2022-12-09 18:48:57 +00:00
// 15.5.5 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-generator-function-definitions-runtime-semantics-evaluation
// FIXME: 1. Let generatorKind be GetGeneratorKind().
// 2. Let exprRef be ? Evaluation of AssignmentExpression.
// 3. Let value be ? GetValue(exprRef).
VERIFY ( m_argument ) ;
TRY ( m_argument - > generate_bytecode ( generator ) ) ;
// 4. Let iteratorRecord be ? GetIterator(value, generatorKind).
// FIXME: Consider generatorKind.
auto iterator_record_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : GetIterator > ( ) ;
generator . emit < Bytecode : : Op : : Store > ( iterator_record_register ) ;
// 5. Let iterator be iteratorRecord.[[Iterator]].
auto iterator_register = generator . allocate_register ( ) ;
auto iterator_identifier = generator . intern_identifier ( " iterator " ) ;
generator . emit < Bytecode : : Op : : GetById > ( iterator_identifier ) ;
generator . emit < Bytecode : : Op : : Store > ( iterator_register ) ;
// Cache iteratorRecord.[[NextMethod]] for use in step 7.a.i.
auto next_method_register = generator . allocate_register ( ) ;
auto next_method_identifier = generator . intern_identifier ( " next " ) ;
generator . emit < Bytecode : : Op : : Load > ( iterator_record_register ) ;
generator . emit < Bytecode : : Op : : GetById > ( next_method_identifier ) ;
generator . emit < Bytecode : : Op : : Store > ( next_method_register ) ;
// 6. Let received be NormalCompletion(undefined).
// See get_received_completion_type_and_value above.
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value ( to_underlying ( Completion : : Type : : Normal ) ) ) ;
generator . emit < Bytecode : : Op : : Store > ( received_completion_type_register ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Store > ( received_completion_value_register ) ;
// 7. Repeat,
auto & loop_block = generator . make_block ( ) ;
auto & continuation_block = generator . make_block ( ) ;
auto & loop_end_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_block } ) ;
generator . switch_to_basic_block ( loop_block ) ;
// a. If received.[[Type]] is normal, then
auto & type_is_normal_block = generator . make_block ( ) ;
auto & is_type_throw_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value ( to_underlying ( Completion : : Type : : Normal ) ) ) ;
generator . emit < Bytecode : : Op : : StrictlyEquals > ( received_completion_type_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { type_is_normal_block } ,
Bytecode : : Label { is_type_throw_block } ) ;
generator . switch_to_basic_block ( type_is_normal_block ) ;
// i. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « received.[[Value]] »).
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2 , AK : : Array { received_completion_value_register , received_completion_value_register } ) ;
generator . emit < Bytecode : : Op : : Call > ( Bytecode : : Op : : Call : : CallType : : Call , next_method_register , iterator_register ) ;
// FIXME: ii. If generatorKind is async, set innerResult to ? Await(innerResult).
// iii. If innerResult is not an Object, throw a TypeError exception.
generator . emit < Bytecode : : Op : : ThrowIfNotObject > ( ) ;
auto inner_result_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( inner_result_register ) ;
// iv. Let done be ? IteratorComplete(innerResult).
generator . emit < Bytecode : : Op : : IteratorResultDone > ( ) ;
// v. If done is true, then
auto & type_is_normal_done_block = generator . make_block ( ) ;
auto & type_is_normal_not_done_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { type_is_normal_done_block } ,
Bytecode : : Label { type_is_normal_not_done_block } ) ;
generator . switch_to_basic_block ( type_is_normal_done_block ) ;
// 1. Return ? IteratorValue(innerResult).
generator . emit < Bytecode : : Op : : Load > ( inner_result_register ) ;
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_end_block } ) ;
generator . switch_to_basic_block ( type_is_normal_not_done_block ) ;
// FIXME: vi. If generatorKind is async, set received to Completion(AsyncGeneratorYield(? IteratorValue(innerResult))).
// vii. Else, set received to Completion(GeneratorYield(innerResult)).
// FIXME: Else,
generator . emit < Bytecode : : Op : : Load > ( inner_result_register ) ;
// FIXME: Yield currently only accepts a Value, not an object conforming to the IteratorResult interface, so we have to do an observable lookup of `value` here.
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( Bytecode : : Label { continuation_block } ) ;
// b. Else if received.[[Type]] is throw, then
generator . switch_to_basic_block ( is_type_throw_block ) ;
auto & type_is_throw_block = generator . make_block ( ) ;
auto & type_is_return_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value ( to_underlying ( Completion : : Type : : Throw ) ) ) ;
generator . emit < Bytecode : : Op : : StrictlyEquals > ( received_completion_type_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { type_is_throw_block } ,
Bytecode : : Label { type_is_return_block } ) ;
generator . switch_to_basic_block ( type_is_throw_block ) ;
// i. Let throw be ? GetMethod(iterator, "throw").
auto throw_method_register = generator . allocate_register ( ) ;
auto throw_identifier = generator . intern_identifier ( " throw " ) ;
generator . emit < Bytecode : : Op : : Load > ( iterator_register ) ;
generator . emit < Bytecode : : Op : : GetMethod > ( throw_identifier ) ;
generator . emit < Bytecode : : Op : : Store > ( throw_method_register ) ;
// ii. If throw is not undefined, then
auto & throw_method_is_defined_block = generator . make_block ( ) ;
auto & throw_method_is_undefined_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : StrictlyInequals > ( throw_method_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { throw_method_is_defined_block } ,
Bytecode : : Label { throw_method_is_undefined_block } ) ;
generator . switch_to_basic_block ( throw_method_is_defined_block ) ;
// 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2 , AK : : Array { received_completion_value_register , received_completion_value_register } ) ;
generator . emit < Bytecode : : Op : : Call > ( Bytecode : : Op : : Call : : CallType : : Call , throw_method_register , iterator_register ) ;
// FIXME: 2. If generatorKind is async, set innerResult to ? Await(innerResult).
// 3. NOTE: Exceptions from the inner iterator throw method are propagated. Normal completions from an inner throw method are processed similarly to an inner next.
// 4. If innerResult is not an Object, throw a TypeError exception.
generator . emit < Bytecode : : Op : : ThrowIfNotObject > ( ) ;
generator . emit < Bytecode : : Op : : Store > ( inner_result_register ) ;
// 5. Let done be ? IteratorComplete(innerResult).
generator . emit < Bytecode : : Op : : IteratorResultDone > ( ) ;
// 6. If done is true, then
auto & type_is_throw_done_block = generator . make_block ( ) ;
auto & type_is_throw_not_done_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { type_is_throw_done_block } ,
Bytecode : : Label { type_is_throw_not_done_block } ) ;
generator . switch_to_basic_block ( type_is_throw_done_block ) ;
// a. Return ? IteratorValue(innerResult).
generator . emit < Bytecode : : Op : : Load > ( inner_result_register ) ;
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_end_block } ) ;
generator . switch_to_basic_block ( type_is_throw_not_done_block ) ;
// FIXME: 7. If generatorKind is async, set received to Completion(AsyncGeneratorYield(? IteratorValue(innerResult))).
// 8. Else, set received to Completion(GeneratorYield(innerResult)).
// FIXME: Else,
generator . emit < Bytecode : : Op : : Load > ( inner_result_register ) ;
// FIXME: Yield currently only accepts a Value, not an object conforming to the IteratorResult interface, so we have to do an observable lookup of `value` here.
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( Bytecode : : Label { continuation_block } ) ;
generator . switch_to_basic_block ( throw_method_is_undefined_block ) ;
// 1. NOTE: If iterator does not have a throw method, this throw is going to terminate the yield* loop. But first we need to give iterator a chance to clean up.
// 2. Let closeCompletion be Completion Record { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }.
// FIXME: 3. If generatorKind is async, perform ? AsyncIteratorClose(iteratorRecord, closeCompletion).
// 4. Else, perform ? IteratorClose(iteratorRecord, closeCompletion).
// FIXME: Else,
generator . emit < Bytecode : : Op : : Load > ( iterator_record_register ) ;
generator . emit < Bytecode : : Op : : IteratorClose > ( Completion : : Type : : Normal , Optional < Value > { } ) ;
// 5. NOTE: The next step throws a TypeError to indicate that there was a yield* protocol violation: iterator does not have a throw method.
// 6. Throw a TypeError exception.
generator . emit < Bytecode : : Op : : NewTypeError > ( generator . intern_string ( ErrorType : : YieldFromIteratorMissingThrowMethod . message ( ) ) ) ;
generator . perform_needed_unwinds < Bytecode : : Op : : Throw > ( ) ;
generator . emit < Bytecode : : Op : : Throw > ( ) ;
// c. Else,
// i. Assert: received.[[Type]] is return.
generator . switch_to_basic_block ( type_is_return_block ) ;
// ii. Let return be ? GetMethod(iterator, "return").
auto return_method_register = generator . allocate_register ( ) ;
auto return_identifier = generator . intern_identifier ( " return " ) ;
generator . emit < Bytecode : : Op : : Load > ( iterator_register ) ;
generator . emit < Bytecode : : Op : : GetMethod > ( return_identifier ) ;
generator . emit < Bytecode : : Op : : Store > ( return_method_register ) ;
// iii. If return is undefined, then
auto & return_is_undefined_block = generator . make_block ( ) ;
auto & return_is_defined_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : StrictlyEquals > ( return_method_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { return_is_undefined_block } ,
Bytecode : : Label { return_is_defined_block } ) ;
generator . switch_to_basic_block ( return_is_undefined_block ) ;
// FIXME: 1. If generatorKind is async, set received.[[Value]] to ? Await(received.[[Value]]).
// 2. Return ? received.
// NOTE: This will always be a return completion.
generator . emit < Bytecode : : Op : : Load > ( received_completion_value_register ) ;
generator . perform_needed_unwinds < Bytecode : : Op : : Yield > ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( nullptr ) ;
generator . switch_to_basic_block ( return_is_defined_block ) ;
// iv. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »).
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2 , AK : : Array { received_completion_value_register , received_completion_value_register } ) ;
generator . emit < Bytecode : : Op : : Call > ( Bytecode : : Op : : Call : : CallType : : Call , return_method_register , iterator_register ) ;
// FIXME: v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
// vi. If innerReturnResult is not an Object, throw a TypeError exception.
generator . emit < Bytecode : : Op : : ThrowIfNotObject > ( ) ;
auto inner_return_result_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( inner_return_result_register ) ;
// vii. Let done be ? IteratorComplete(innerReturnResult).
generator . emit < Bytecode : : Op : : IteratorResultDone > ( ) ;
// viii. If done is true, then
auto & type_is_return_done_block = generator . make_block ( ) ;
auto & type_is_return_not_done_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { type_is_return_done_block } ,
Bytecode : : Label { type_is_return_not_done_block } ) ;
generator . switch_to_basic_block ( type_is_return_done_block ) ;
// 1. Let value be ? IteratorValue(innerReturnResult).
generator . emit < Bytecode : : Op : : Load > ( inner_result_register ) ;
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
// 2. Return Completion Record { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
generator . perform_needed_unwinds < Bytecode : : Op : : Yield > ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( nullptr ) ;
generator . switch_to_basic_block ( type_is_return_not_done_block ) ;
// FIXME: ix. If generatorKind is async, set received to Completion(AsyncGeneratorYield(? IteratorValue(innerReturnResult))).
// x. Else, set received to Completion(GeneratorYield(innerReturnResult)).
// FIXME: Else,
generator . emit < Bytecode : : Op : : Load > ( inner_return_result_register ) ;
// FIXME: Yield currently only accepts a Value, not an object conforming to the IteratorResult interface, so we have to do an observable lookup of `value` here.
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( Bytecode : : Label { continuation_block } ) ;
generator . switch_to_basic_block ( continuation_block ) ;
get_received_completion_type_and_value ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_block } ) ;
generator . switch_to_basic_block ( loop_end_block ) ;
return { } ;
2022-02-12 19:54:08 +03:30
}
2021-06-14 15:46:41 +04:30
2021-06-11 01:38:30 +04:30
if ( m_argument )
2022-02-12 19:54:08 +03:30
TRY ( m_argument - > generate_bytecode ( generator ) ) ;
2022-11-25 23:14:27 +00:00
else
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2021-06-11 01:38:30 +04:30
auto & continuation_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( Bytecode : : Label { continuation_block } ) ;
generator . switch_to_basic_block ( continuation_block ) ;
2022-11-25 23:14:08 +00:00
get_received_completion_type_and_value ( ) ;
auto & normal_completion_continuation_block = generator . make_block ( ) ;
auto & throw_completion_continuation_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value ( to_underlying ( Completion : : Type : : Normal ) ) ) ;
generator . emit < Bytecode : : Op : : StrictlyEquals > ( received_completion_type_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { normal_completion_continuation_block } ,
Bytecode : : Label { throw_completion_continuation_block } ) ;
auto & throw_value_block = generator . make_block ( ) ;
auto & return_value_block = generator . make_block ( ) ;
generator . switch_to_basic_block ( throw_completion_continuation_block ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value ( to_underlying ( Completion : : Type : : Throw ) ) ) ;
generator . emit < Bytecode : : Op : : StrictlyEquals > ( received_completion_type_register ) ;
// If type is not equal to "throw" or "normal", assume it's "return".
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { throw_value_block } ,
Bytecode : : Label { return_value_block } ) ;
generator . switch_to_basic_block ( throw_value_block ) ;
generator . emit < Bytecode : : Op : : Load > ( received_completion_value_register ) ;
generator . perform_needed_unwinds < Bytecode : : Op : : Throw > ( ) ;
generator . emit < Bytecode : : Op : : Throw > ( ) ;
generator . switch_to_basic_block ( return_value_block ) ;
generator . emit < Bytecode : : Op : : Load > ( received_completion_value_register ) ;
generator . perform_needed_unwinds < Bytecode : : Op : : Yield > ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( nullptr ) ;
generator . switch_to_basic_block ( normal_completion_continuation_block ) ;
generator . emit < Bytecode : : Op : : Load > ( received_completion_value_register ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-05 15:53:36 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > IfStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-06 13:26:50 +02:00
{
2021-06-09 06:49:58 +04:30
// test
// jump if_true (true) true (false) false
// true
// jump always (true) end
// false
// jump always (true) end
// end
auto & true_block = generator . make_block ( ) ;
auto & false_block = generator . make_block ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_predicate - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { true_block } ,
Bytecode : : Label { false_block } ) ;
Bytecode : : Op : : Jump * true_block_jump { nullptr } ;
2021-06-06 13:26:50 +02:00
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( true_block ) ;
2021-06-20 12:38:59 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_consequent - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
if ( ! generator . is_current_block_terminated ( ) )
true_block_jump = & generator . emit < Bytecode : : Op : : Jump > ( ) ;
generator . switch_to_basic_block ( false_block ) ;
2021-06-20 12:38:59 +02:00
auto & end_block = generator . make_block ( ) ;
2021-06-09 06:49:58 +04:30
2021-06-20 12:38:59 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
if ( m_alternate )
2022-02-12 19:54:08 +03:30
TRY ( m_alternate - > generate_bytecode ( generator ) ) ;
2021-06-20 12:38:59 +02:00
if ( ! generator . is_current_block_terminated ( ) )
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { end_block } , { } ) ;
2021-06-09 06:49:58 +04:30
2021-06-20 12:38:59 +02:00
if ( true_block_jump )
true_block_jump - > set_targets ( Bytecode : : Label { end_block } , { } ) ;
2021-06-09 06:49:58 +04:30
2021-06-20 12:38:59 +02:00
generator . switch_to_basic_block ( end_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-06 13:26:50 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ContinueStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-06 13:33:02 +02:00
{
2022-11-13 20:56:53 +01:00
// FIXME: Handle finally blocks in a graceful manner
// We need to execute the finally block, but tell it to resume
// execution at the designated block
2022-06-11 23:09:37 +01:00
if ( m_target_label . is_null ( ) ) {
2022-11-25 16:35:39 +01:00
generator . generate_continue ( ) ;
2022-06-11 23:09:37 +01:00
return { } ;
}
2022-11-25 16:35:39 +01:00
generator . generate_continue ( m_target_label ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-06 13:33:02 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > DebuggerStatement : : generate_bytecode ( Bytecode : : Generator & ) const
2021-06-07 20:05:50 +01:00
{
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 20:05:50 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ConditionalExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 04:54:34 +01:00
{
2021-06-09 06:49:58 +04:30
// test
// jump if_true (true) true (false) false
// true
// jump always (true) end
// false
// jump always (true) end
// end
auto & true_block = generator . make_block ( ) ;
auto & false_block = generator . make_block ( ) ;
auto & end_block = generator . make_block ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_test - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { true_block } ,
Bytecode : : Label { false_block } ) ;
2021-06-08 04:54:34 +01:00
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( true_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_consequent - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { end_block } ,
{ } ) ;
2021-06-08 04:54:34 +01:00
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( false_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_alternate - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { end_block } ,
{ } ) ;
2021-06-08 04:54:34 +01:00
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( end_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 04:54:34 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > SequenceExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 10:13:37 +01:00
{
for ( auto & expression : m_expressions )
2023-03-06 14:17:01 +01:00
TRY ( expression - > generate_bytecode ( generator ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 10:13:37 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > TemplateLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 19:14:01 +02:00
{
2021-06-07 20:58:36 -07:00
auto string_reg = generator . allocate_register ( ) ;
2021-06-08 19:14:01 +02:00
2021-06-07 20:58:36 -07:00
for ( size_t i = 0 ; i < m_expressions . size ( ) ; i + + ) {
2023-03-06 14:17:01 +01:00
TRY ( m_expressions [ i ] - > generate_bytecode ( generator ) ) ;
2021-06-07 20:58:36 -07:00
if ( i = = 0 ) {
generator . emit < Bytecode : : Op : : Store > ( string_reg ) ;
} else {
generator . emit < Bytecode : : Op : : ConcatString > ( string_reg ) ;
}
2021-06-08 19:14:01 +02:00
}
2021-06-09 21:11:04 +02:00
generator . emit < Bytecode : : Op : : Load > ( string_reg ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 19:14:01 +02:00
}
2021-06-09 11:40:38 +02:00
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > TaggedTemplateLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-09 21:02:24 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( m_tag - > generate_bytecode ( generator ) ) ;
2021-06-09 22:07:18 +02:00
auto tag_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( tag_reg ) ;
2022-09-07 23:39:43 +02:00
// FIXME: We only need to record the first and last register,
// due to packing everything in an array, same goes for argument_regs
2023-06-25 12:31:49 +02:00
// FIXME: Follow
// 13.2.8.3 GetTemplateObject ( templateLiteral ), https://tc39.es/ecma262/#sec-gettemplateobject
// more closely, namely:
// * cache this somehow
// * add a raw object accessor
// * freeze array and raw member
2021-06-09 21:02:24 +02:00
Vector < Bytecode : : Register > string_regs ;
auto & expressions = m_template_literal - > expressions ( ) ;
2022-03-14 14:48:42 +00:00
for ( size_t i = 0 ; i < expressions . size ( ) ; + + i ) {
if ( i % 2 ! = 0 )
continue ;
string_regs . append ( generator . allocate_register ( ) ) ;
}
size_t reg_index = 0 ;
2021-06-09 21:02:24 +02:00
for ( size_t i = 0 ; i < expressions . size ( ) ; + + i ) {
if ( i % 2 ! = 0 )
continue ;
2023-06-25 12:31:49 +02:00
// NOTE: If the string contains invalid escapes we get a null expression here,
// which we then convert to the expected `undefined` TV. See
// 12.9.6.1 Static Semantics: TV, https://tc39.es/ecma262/#sec-static-semantics-tv
if ( is < NullLiteral > ( expressions [ i ] ) )
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
else
TRY ( expressions [ i ] - > generate_bytecode ( generator ) ) ;
2021-06-09 21:02:24 +02:00
2022-03-14 14:48:42 +00:00
auto string_reg = string_regs [ reg_index + + ] ;
2021-06-09 21:02:24 +02:00
generator . emit < Bytecode : : Op : : Store > ( string_reg ) ;
}
2022-03-14 14:48:42 +00:00
if ( string_regs . is_empty ( ) ) {
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
} else {
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2u , AK : : Array { string_regs . first ( ) , string_regs . last ( ) } ) ;
}
2021-06-09 21:02:24 +02:00
auto strings_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( strings_reg ) ;
Vector < Bytecode : : Register > argument_regs ;
argument_regs . append ( strings_reg ) ;
2022-09-07 23:39:43 +02:00
for ( size_t i = 1 ; i < expressions . size ( ) ; i + = 2 )
argument_regs . append ( generator . allocate_register ( ) ) ;
2021-06-09 21:02:24 +02:00
2022-09-07 23:39:43 +02:00
for ( size_t i = 1 ; i < expressions . size ( ) ; i + = 2 ) {
auto string_reg = argument_regs [ 1 + i / 2 ] ;
2023-03-06 14:17:01 +01:00
TRY ( expressions [ i ] - > generate_bytecode ( generator ) ) ;
2021-06-09 21:02:24 +02:00
generator . emit < Bytecode : : Op : : Store > ( string_reg ) ;
}
Vector < Bytecode : : Register > raw_string_regs ;
2022-03-14 14:48:42 +00:00
for ( [[maybe_unused]] auto & raw_string : m_template_literal - > raw_strings ( ) )
string_regs . append ( generator . allocate_register ( ) ) ;
reg_index = 0 ;
2021-06-09 21:02:24 +02:00
for ( auto & raw_string : m_template_literal - > raw_strings ( ) ) {
2023-03-06 14:17:01 +01:00
TRY ( raw_string - > generate_bytecode ( generator ) ) ;
2022-03-14 14:48:42 +00:00
auto raw_string_reg = string_regs [ reg_index + + ] ;
2021-06-09 21:02:24 +02:00
generator . emit < Bytecode : : Op : : Store > ( raw_string_reg ) ;
raw_string_regs . append ( raw_string_reg ) ;
}
2022-03-14 14:48:42 +00:00
if ( raw_string_regs . is_empty ( ) ) {
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
} else {
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2u , AK : : Array { raw_string_regs . first ( ) , raw_string_regs . last ( ) } ) ;
}
2021-06-09 21:02:24 +02:00
auto raw_strings_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( raw_strings_reg ) ;
2023-06-15 16:36:14 +02:00
generator . emit < Bytecode : : Op : : PutById > ( strings_reg , generator . intern_identifier ( " raw " ) ) ;
2021-06-09 21:02:24 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
auto this_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( this_reg ) ;
2022-09-07 23:39:43 +02:00
if ( ! argument_regs . is_empty ( ) )
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2 , AK : : Array { argument_regs . first ( ) , argument_regs . last ( ) } ) ;
else
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
generator . emit < Bytecode : : Op : : Call > ( Bytecode : : Op : : Call : : CallType : : Call , tag_reg , this_reg ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-09 21:02:24 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > UpdateExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-09 11:40:38 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( generator . emit_load_from_reference ( * m_argument ) ) ;
2021-06-09 11:40:38 +02:00
2021-10-25 15:17:41 +02:00
Optional < Bytecode : : Register > previous_value_for_postfix_reg ;
if ( ! m_prefixed ) {
previous_value_for_postfix_reg = generator . allocate_register ( ) ;
2023-06-16 10:51:40 +02:00
generator . emit < Bytecode : : Op : : ToNumeric > ( ) ;
2021-10-25 15:17:41 +02:00
generator . emit < Bytecode : : Op : : Store > ( * previous_value_for_postfix_reg ) ;
}
2021-06-09 11:40:38 +02:00
2021-10-25 15:17:41 +02:00
if ( m_op = = UpdateOp : : Increment )
generator . emit < Bytecode : : Op : : Increment > ( ) ;
else
generator . emit < Bytecode : : Op : : Decrement > ( ) ;
2021-06-09 11:40:38 +02:00
2022-02-12 19:54:08 +03:30
TRY ( generator . emit_store_to_reference ( * m_argument ) ) ;
2021-06-09 11:40:38 +02:00
2021-10-25 15:17:41 +02:00
if ( ! m_prefixed )
generator . emit < Bytecode : : Op : : Load > ( * previous_value_for_postfix_reg ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-09 11:40:38 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ThrowStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-09 18:18:56 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( m_argument - > generate_bytecode ( generator ) ) ;
2022-03-14 02:26:39 +00:00
generator . perform_needed_unwinds < Bytecode : : Op : : Throw > ( ) ;
2021-06-09 18:18:56 +02:00
generator . emit < Bytecode : : Op : : Throw > ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-09 18:18:56 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > BreakStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-10 20:28:43 +08:00
{
2022-11-13 20:56:53 +01:00
// FIXME: Handle finally blocks in a graceful manner
// We need to execute the finally block, but tell it to resume
// execution at the designated block
2022-06-11 23:09:37 +01:00
if ( m_target_label . is_null ( ) ) {
2022-11-25 16:15:34 +01:00
generator . generate_break ( ) ;
2022-06-11 23:09:37 +01:00
return { } ;
}
2022-11-25 16:15:34 +01:00
generator . generate_break ( m_target_label ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-10 20:28:43 +08:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > TryStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-10 15:04:38 +02:00
{
auto & saved_block = generator . current_block ( ) ;
Optional < Bytecode : : Label > handler_target ;
Optional < Bytecode : : Label > finalizer_target ;
Bytecode : : BasicBlock * next_block { nullptr } ;
if ( m_finalizer ) {
2022-11-25 16:15:34 +01:00
// FIXME: See notes in Op.h->ScheduleJump
2021-06-10 15:04:38 +02:00
auto & finalizer_block = generator . make_block ( ) ;
generator . switch_to_basic_block ( finalizer_block ) ;
2022-11-13 15:58:36 +01:00
generator . emit < Bytecode : : Op : : LeaveUnwindContext > ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_finalizer - > generate_bytecode ( generator ) ) ;
2021-06-10 15:04:38 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
next_block = & generator . make_block ( ) ;
auto next_target = Bytecode : : Label { * next_block } ;
generator . emit < Bytecode : : Op : : ContinuePendingUnwind > ( next_target ) ;
}
finalizer_target = Bytecode : : Label { finalizer_block } ;
}
2022-11-13 20:56:53 +01:00
if ( m_finalizer )
generator . start_boundary ( Bytecode : : Generator : : BlockBoundaryType : : ReturnToFinally ) ;
2021-06-10 15:04:38 +02:00
if ( m_handler ) {
auto & handler_block = generator . make_block ( ) ;
generator . switch_to_basic_block ( handler_block ) ;
2022-11-13 20:56:53 +01:00
if ( ! m_finalizer )
generator . emit < Bytecode : : Op : : LeaveUnwindContext > ( ) ;
2023-06-16 16:34:47 +02:00
generator . begin_variable_scope ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_handler - > parameter ( ) . visit (
2023-01-08 19:23:00 -05:00
[ & ] ( DeprecatedFlyString const & parameter ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-10-24 22:46:54 +02:00
if ( ! parameter . is_empty ( ) ) {
2022-03-14 02:38:13 +00:00
auto parameter_identifier = generator . intern_identifier ( parameter ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( parameter_identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( parameter_identifier , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
2021-07-11 15:15:38 +04:30
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-07-11 15:15:38 +04:30
} ,
2023-06-24 20:29:30 +02:00
[ & ] ( NonnullRefPtr < BindingPattern const > const & binding_pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
auto value_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( value_register ) ;
TRY ( generate_binding_pattern_bytecode ( generator , * binding_pattern , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , value_register , true ) ) ;
return { } ;
2022-02-12 19:54:08 +03:30
} ) ) ;
2021-07-11 15:15:38 +04:30
2023-06-25 20:52:06 +01:00
// Set accumulator to undefined, otherwise we leak the error object through the accumulator.
// For example: `try { BigInt.call() } catch {}` would result in the error object. Note that
// the exception _is_ caught here, it just leaks the error object through to the result.
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_handler - > body ( ) . generate_bytecode ( generator ) ) ;
2021-06-10 15:04:38 +02:00
handler_target = Bytecode : : Label { handler_block } ;
2022-03-14 02:38:13 +00:00
generator . end_variable_scope ( ) ;
2021-06-10 15:04:38 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
if ( m_finalizer ) {
generator . emit < Bytecode : : Op : : Jump > ( finalizer_target ) ;
} else {
VERIFY ( ! next_block ) ;
next_block = & generator . make_block ( ) ;
auto next_target = Bytecode : : Label { * next_block } ;
generator . emit < Bytecode : : Op : : Jump > ( next_target ) ;
}
}
}
2022-11-13 20:56:53 +01:00
if ( m_finalizer )
generator . end_boundary ( Bytecode : : Generator : : BlockBoundaryType : : ReturnToFinally ) ;
2021-06-10 15:04:38 +02:00
2021-06-13 20:39:40 +04:30
auto & target_block = generator . make_block ( ) ;
2021-06-10 15:04:38 +02:00
generator . switch_to_basic_block ( saved_block ) ;
2021-06-13 20:39:40 +04:30
generator . emit < Bytecode : : Op : : EnterUnwindContext > ( Bytecode : : Label { target_block } , handler_target , finalizer_target ) ;
2022-03-13 11:51:02 +03:30
generator . start_boundary ( Bytecode : : Generator : : BlockBoundaryType : : Unwind ) ;
2022-11-13 20:56:53 +01:00
if ( m_finalizer )
generator . start_boundary ( Bytecode : : Generator : : BlockBoundaryType : : ReturnToFinally ) ;
2021-06-13 20:39:40 +04:30
generator . switch_to_basic_block ( target_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_block - > generate_bytecode ( generator ) ) ;
2021-11-10 22:22:26 +03:30
if ( ! generator . is_current_block_terminated ( ) ) {
if ( m_finalizer ) {
generator . emit < Bytecode : : Op : : Jump > ( finalizer_target ) ;
} else {
2023-05-13 18:50:27 +02:00
if ( ! next_block )
next_block = & generator . make_block ( ) ;
2022-11-13 18:38:15 +01:00
generator . emit < Bytecode : : Op : : LeaveUnwindContext > ( ) ;
2023-05-13 18:50:27 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { * next_block } ) ;
2021-11-10 22:22:26 +03:30
}
}
2022-11-13 20:56:53 +01:00
if ( m_finalizer )
generator . end_boundary ( Bytecode : : Generator : : BlockBoundaryType : : ReturnToFinally ) ;
2022-03-13 11:51:02 +03:30
generator . end_boundary ( Bytecode : : Generator : : BlockBoundaryType : : Unwind ) ;
2021-06-10 15:04:38 +02:00
generator . switch_to_basic_block ( next_block ? * next_block : saved_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-10 15:04:38 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > SwitchStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
2023-01-08 19:23:00 -05:00
Bytecode : : CodeGenerationErrorOr < void > SwitchStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set ) const
2021-06-11 00:36:16 +02:00
{
auto discriminant_reg = generator . allocate_register ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_discriminant - > generate_bytecode ( generator ) ) ;
2021-06-11 00:36:16 +02:00
generator . emit < Bytecode : : Op : : Store > ( discriminant_reg ) ;
Vector < Bytecode : : BasicBlock & > case_blocks ;
Bytecode : : BasicBlock * default_block { nullptr } ;
Bytecode : : BasicBlock * next_test_block = & generator . make_block ( ) ;
2022-04-03 02:13:51 +04:30
2023-06-25 07:37:24 +02:00
auto has_lexical_declarations = this - > has_lexical_declarations ( ) ;
if ( has_lexical_declarations )
generator . block_declaration_instantiation ( * this ) ;
2022-04-03 02:13:51 +04:30
2021-06-11 00:36:16 +02:00
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { * next_test_block } , { } ) ;
2022-04-03 02:13:51 +04:30
2021-06-11 00:36:16 +02:00
for ( auto & switch_case : m_cases ) {
auto & case_block = generator . make_block ( ) ;
2023-03-06 14:17:01 +01:00
if ( switch_case - > test ( ) ) {
2021-06-11 00:36:16 +02:00
generator . switch_to_basic_block ( * next_test_block ) ;
2023-03-06 14:17:01 +01:00
TRY ( switch_case - > test ( ) - > generate_bytecode ( generator ) ) ;
2021-09-24 00:06:10 +02:00
generator . emit < Bytecode : : Op : : StrictlyEquals > ( discriminant_reg ) ;
2021-06-11 00:36:16 +02:00
next_test_block = & generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets ( Bytecode : : Label { case_block } , Bytecode : : Label { * next_test_block } ) ;
} else {
default_block = & case_block ;
}
case_blocks . append ( case_block ) ;
}
generator . switch_to_basic_block ( * next_test_block ) ;
auto & end_block = generator . make_block ( ) ;
if ( default_block ! = nullptr ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { * default_block } , { } ) ;
} else {
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { end_block } , { } ) ;
}
auto current_block = case_blocks . begin ( ) ;
2022-06-11 23:09:37 +01:00
generator . begin_breakable_scope ( Bytecode : : Label { end_block } , label_set ) ;
2021-06-11 00:36:16 +02:00
for ( auto & switch_case : m_cases ) {
generator . switch_to_basic_block ( * current_block ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2023-03-06 14:17:01 +01:00
for ( auto & statement : switch_case - > children ( ) ) {
TRY ( statement - > generate_bytecode ( generator ) ) ;
2022-03-15 01:43:44 +00:00
if ( generator . is_current_block_terminated ( ) )
break ;
2021-06-11 00:36:16 +02:00
}
if ( ! generator . is_current_block_terminated ( ) ) {
auto next_block = current_block ;
next_block + + ;
if ( next_block . is_end ( ) ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { end_block } , { } ) ;
} else {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { * next_block } , { } ) ;
}
}
current_block + + ;
}
generator . end_breakable_scope ( ) ;
generator . switch_to_basic_block ( end_block ) ;
2023-06-25 07:37:24 +02:00
if ( has_lexical_declarations )
generator . end_variable_scope ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-11 00:36:16 +02:00
}
2022-02-12 19:55:40 +03:30
Bytecode : : CodeGenerationErrorOr < void > ClassDeclaration : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-30 15:42:13 -03:00
{
2022-02-12 19:55:40 +03:30
TRY ( m_class_expression - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( m_class_expression . ptr ( ) - > name ( ) ) , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
return { } ;
}
2023-06-23 14:27:42 +02:00
Bytecode : : CodeGenerationErrorOr < void > ClassExpression : : generate_bytecode_with_lhs_name ( Bytecode : : Generator & generator , Optional < DeprecatedFlyString const & > lhs_name ) const
2022-02-12 19:55:40 +03:30
{
2023-06-23 14:27:42 +02:00
generator . emit < Bytecode : : Op : : NewClass > ( * this , lhs_name ) ;
2022-02-12 19:55:40 +03:30
return { } ;
2021-06-30 15:42:13 -03:00
}
2023-06-23 14:27:42 +02:00
Bytecode : : CodeGenerationErrorOr < void > ClassExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
return generate_bytecode_with_lhs_name ( generator , { } ) ;
}
2022-09-02 23:39:04 +02:00
Bytecode : : CodeGenerationErrorOr < void > SpreadExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
// NOTE: All users of this should handle the behaviour of this on their own,
// assuming it returns an Array-like object
return m_target - > generate_bytecode ( generator ) ;
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ThisExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-10-24 14:43:00 +02:00
{
generator . emit < Bytecode : : Op : : ResolveThisBinding > ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-10-24 14:43:00 +02:00
}
2023-06-27 19:24:34 +01:00
static void generate_await ( Bytecode : : Generator & generator )
2021-11-11 00:46:07 +03:30
{
VERIFY ( generator . is_in_async_function ( ) ) ;
2022-12-25 17:15:29 +01:00
// Transform `await expr` to `yield expr`, see AsyncFunctionDriverWrapper
// For that we just need to copy most of the code from YieldExpression
auto received_completion_register = generator . allocate_register ( ) ;
auto received_completion_type_register = generator . allocate_register ( ) ;
auto received_completion_value_register = generator . allocate_register ( ) ;
auto type_identifier = generator . intern_identifier ( " type " ) ;
auto value_identifier = generator . intern_identifier ( " value " ) ;
2021-11-11 00:46:07 +03:30
auto & continuation_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( Bytecode : : Label { continuation_block } ) ;
generator . switch_to_basic_block ( continuation_block ) ;
2022-12-25 17:15:29 +01:00
// The accumulator is set to an object, for example: { "type": 1 (normal), value: 1337 }
generator . emit < Bytecode : : Op : : Store > ( received_completion_register ) ;
generator . emit < Bytecode : : Op : : GetById > ( type_identifier ) ;
generator . emit < Bytecode : : Op : : Store > ( received_completion_type_register ) ;
generator . emit < Bytecode : : Op : : Load > ( received_completion_register ) ;
generator . emit < Bytecode : : Op : : GetById > ( value_identifier ) ;
generator . emit < Bytecode : : Op : : Store > ( received_completion_value_register ) ;
auto & normal_completion_continuation_block = generator . make_block ( ) ;
auto & throw_value_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value ( to_underlying ( Completion : : Type : : Normal ) ) ) ;
generator . emit < Bytecode : : Op : : StrictlyEquals > ( received_completion_type_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > (
Bytecode : : Label { normal_completion_continuation_block } ,
Bytecode : : Label { throw_value_block } ) ;
// Simplification: The only abrupt completion we receive from AsyncFunctionDriverWrapper is Type::Throw
// So we do not need to account for the Type::Return path
generator . switch_to_basic_block ( throw_value_block ) ;
generator . emit < Bytecode : : Op : : Load > ( received_completion_value_register ) ;
generator . perform_needed_unwinds < Bytecode : : Op : : Throw > ( ) ;
generator . emit < Bytecode : : Op : : Throw > ( ) ;
generator . switch_to_basic_block ( normal_completion_continuation_block ) ;
generator . emit < Bytecode : : Op : : Load > ( received_completion_value_register ) ;
2023-06-27 19:24:34 +01:00
}
Bytecode : : CodeGenerationErrorOr < void > AwaitExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
TRY ( m_argument - > generate_bytecode ( generator ) ) ;
generate_await ( generator ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-11-11 00:46:07 +03:30
}
2022-03-13 16:01:18 +03:30
Bytecode : : CodeGenerationErrorOr < void > WithStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
TRY ( m_object - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : EnterObjectEnvironment > ( ) ;
2022-03-14 02:35:45 +00:00
// EnterObjectEnvironment sets the running execution context's lexical_environment to a new Object Environment.
generator . start_boundary ( Bytecode : : Generator : : BlockBoundaryType : : LeaveLexicalEnvironment ) ;
2022-03-13 16:01:18 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
2022-03-14 02:35:45 +00:00
generator . end_boundary ( Bytecode : : Generator : : BlockBoundaryType : : LeaveLexicalEnvironment ) ;
if ( ! generator . is_current_block_terminated ( ) )
2023-06-16 16:43:24 +02:00
generator . emit < Bytecode : : Op : : LeaveLexicalEnvironment > ( ) ;
2022-03-14 02:35:45 +00:00
2022-03-13 16:01:18 +03:30
return { } ;
}
2022-03-18 20:18:19 +03:30
enum class LHSKind {
Assignment ,
VarBinding ,
LexicalBinding ,
} ;
enum class IterationKind {
Enumerate ,
Iterate ,
AsyncIterate ,
} ;
// 14.7.5.6 ForIn/OfHeadEvaluation ( uninitializedBoundNames, expr, iterationKind ), https://tc39.es/ecma262/#sec-runtime-semantics-forinofheadevaluation
struct ForInOfHeadEvaluationResult {
bool is_destructuring { false } ;
LHSKind lhs_kind { LHSKind : : Assignment } ;
} ;
2023-02-19 22:07:52 +01:00
static Bytecode : : CodeGenerationErrorOr < ForInOfHeadEvaluationResult > for_in_of_head_evaluation ( Bytecode : : Generator & generator , IterationKind iteration_kind , Variant < NonnullRefPtr < ASTNode const > , NonnullRefPtr < BindingPattern const > > const & lhs , NonnullRefPtr < ASTNode const > const & rhs )
2022-03-18 20:18:19 +03:30
{
ForInOfHeadEvaluationResult result { } ;
2022-10-19 17:42:54 +02:00
bool entered_lexical_scope = false ;
2023-02-19 22:07:52 +01:00
if ( auto * ast_ptr = lhs . get_pointer < NonnullRefPtr < ASTNode const > > ( ) ; ast_ptr & & is < VariableDeclaration > ( * * ast_ptr ) ) {
2022-03-18 20:18:19 +03:30
// Runtime Semantics: ForInOfLoopEvaluation, for any of:
// ForInOfStatement : for ( var ForBinding in Expression ) Statement
// ForInOfStatement : for ( ForDeclaration in Expression ) Statement
// ForInOfStatement : for ( var ForBinding of AssignmentExpression ) Statement
// ForInOfStatement : for ( ForDeclaration of AssignmentExpression ) Statement
auto & variable_declaration = static_cast < VariableDeclaration const & > ( * * ast_ptr ) ;
2023-03-06 14:17:01 +01:00
result . is_destructuring = variable_declaration . declarations ( ) . first ( ) - > target ( ) . has < NonnullRefPtr < BindingPattern const > > ( ) ;
2022-03-18 20:18:19 +03:30
result . lhs_kind = variable_declaration . is_lexical_declaration ( ) ? LHSKind : : LexicalBinding : LHSKind : : VarBinding ;
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
// NOTE: 'uninitializedBoundNames' refers to the lexical bindings (i.e. Const/Let) present in the second and last form.
// 2. If uninitializedBoundNames is not an empty List, then
2022-10-19 17:42:54 +02:00
2022-03-18 20:18:19 +03:30
if ( variable_declaration . declaration_kind ( ) ! = DeclarationKind : : Var ) {
entered_lexical_scope = true ;
// a. Assert: uninitializedBoundNames has no duplicate entries.
// b. Let newEnv be NewDeclarativeEnvironment(oldEnv).
generator . begin_variable_scope ( ) ;
// c. For each String name of uninitializedBoundNames, do
2023-02-27 22:13:37 +00:00
// NOTE: Nothing in the callback throws an exception.
MUST ( variable_declaration . for_each_bound_name ( [ & ] ( auto const & name ) {
2022-03-18 20:18:19 +03:30
// i. Perform ! newEnv.CreateMutableBinding(name, false).
auto identifier = generator . intern_identifier ( name ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
2023-02-27 22:13:37 +00:00
} ) ) ;
2022-03-18 20:18:19 +03:30
// d. Set the running execution context's LexicalEnvironment to newEnv.
2023-06-16 16:43:24 +02:00
// NOTE: Done by CreateLexicalEnvironment.
2022-03-18 20:18:19 +03:30
}
} else {
// Runtime Semantics: ForInOfLoopEvaluation, for any of:
// ForInOfStatement : for ( LeftHandSideExpression in Expression ) Statement
// ForInOfStatement : for ( LeftHandSideExpression of AssignmentExpression ) Statement
result . lhs_kind = LHSKind : : Assignment ;
2022-10-19 17:42:54 +02:00
}
2022-03-18 20:18:19 +03:30
2022-10-19 17:42:54 +02:00
// 3. Let exprRef be the result of evaluating expr.
TRY ( rhs - > generate_bytecode ( generator ) ) ;
// 4. Set the running execution context's LexicalEnvironment to oldEnv.
if ( entered_lexical_scope )
generator . end_variable_scope ( ) ;
2022-03-18 20:18:19 +03:30
2022-10-19 17:42:54 +02:00
// 5. Let exprValue be ? GetValue(exprRef).
// NOTE: No need to store this anywhere.
2022-03-18 20:18:19 +03:30
2022-10-19 17:42:54 +02:00
// 6. If iterationKind is enumerate, then
if ( iteration_kind = = IterationKind : : Enumerate ) {
// a. If exprValue is undefined or null, then
auto & nullish_block = generator . make_block ( ) ;
auto & continuation_block = generator . make_block ( ) ;
auto & jump = generator . emit < Bytecode : : Op : : JumpNullish > ( ) ;
jump . set_targets ( Bytecode : : Label { nullish_block } , Bytecode : : Label { continuation_block } ) ;
// i. Return Completion Record { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }.
generator . switch_to_basic_block ( nullish_block ) ;
2022-11-25 16:42:29 +01:00
generator . generate_break ( ) ;
2022-10-19 17:42:54 +02:00
generator . switch_to_basic_block ( continuation_block ) ;
// b. Let obj be ! ToObject(exprValue).
// NOTE: GetObjectPropertyIterator does this.
// c. Let iterator be EnumerateObjectProperties(obj).
// d. Let nextMethod be ! GetV(iterator, "next").
// e. Return the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
generator . emit < Bytecode : : Op : : GetObjectPropertyIterator > ( ) ;
}
// 7. Else,
else {
2022-03-18 20:18:19 +03:30
// a. Assert: iterationKind is iterate or async-iterate.
// b. If iterationKind is async-iterate, let iteratorHint be async.
// c. Else, let iteratorHint be sync.
2023-06-27 19:24:34 +01:00
auto iterator_hint = iteration_kind = = IterationKind : : AsyncIterate ? IteratorHint : : Async : IteratorHint : : Sync ;
2022-03-18 20:18:19 +03:30
// d. Return ? GetIterator(exprValue, iteratorHint).
2023-06-27 19:24:34 +01:00
generator . emit < Bytecode : : Op : : GetIterator > ( iterator_hint ) ;
2022-03-18 20:18:19 +03:30
}
return result ;
}
// 14.7.5.7 ForIn/OfBodyEvaluation ( lhs, stmt, iteratorRecord, iterationKind, lhsKind, labelSet [ , iteratorKind ] ), https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset
2023-06-27 19:24:34 +01:00
static Bytecode : : CodeGenerationErrorOr < void > for_in_of_body_evaluation ( Bytecode : : Generator & generator , ASTNode const & node , Variant < NonnullRefPtr < ASTNode const > , NonnullRefPtr < BindingPattern const > > const & lhs , ASTNode const & body , ForInOfHeadEvaluationResult const & head_result , Vector < DeprecatedFlyString > const & label_set , Bytecode : : BasicBlock & loop_end , Bytecode : : BasicBlock & loop_update , IteratorHint iterator_kind = IteratorHint : : Sync )
2022-03-18 20:18:19 +03:30
{
auto iterator_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( iterator_register ) ;
2023-06-27 19:24:34 +01:00
// 1. If iteratorKind is not present, set iteratorKind to sync.
2022-03-18 20:18:19 +03:30
// 2. Let oldEnv be the running execution context's LexicalEnvironment.
bool has_lexical_binding = false ;
// 3. Let V be undefined.
// NOTE: We don't need 'V' as the resulting value will naturally flow through via the accumulator register.
// 4. Let destructuring be IsDestructuring of lhs.
auto destructuring = head_result . is_destructuring ;
// 5. If destructuring is true and if lhsKind is assignment, then
2022-12-09 18:47:51 +00:00
if ( destructuring & & head_result . lhs_kind = = LHSKind : : Assignment ) {
2022-03-18 20:18:19 +03:30
// a. Assert: lhs is a LeftHandSideExpression.
// b. Let assignmentPattern be the AssignmentPattern that is covered by lhs.
// FIXME: Implement this.
return Bytecode : : CodeGenerationError {
& node ,
2022-12-09 18:47:51 +00:00
" Unimplemented: assignment destructuring in for/of " sv ,
2022-03-18 20:18:19 +03:30
} ;
}
// 6. Repeat,
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_update } ) ;
generator . switch_to_basic_block ( loop_update ) ;
2022-06-11 23:09:37 +01:00
generator . begin_continuable_scope ( Bytecode : : Label { loop_update } , label_set ) ;
2022-03-18 20:18:19 +03:30
// a. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
generator . emit < Bytecode : : Op : : Load > ( iterator_register ) ;
generator . emit < Bytecode : : Op : : IteratorNext > ( ) ;
2023-06-27 19:24:34 +01:00
// b. If iteratorKind is async, set nextResult to ? Await(nextResult).
if ( iterator_kind = = IteratorHint : : Async )
generate_await ( generator ) ;
2022-03-18 20:18:19 +03:30
// c. If Type(nextResult) is not Object, throw a TypeError exception.
2023-06-27 19:24:34 +01:00
generator . emit < Bytecode : : Op : : ThrowIfNotObject > ( ) ;
2022-03-18 20:18:19 +03:30
// d. Let done be ? IteratorComplete(nextResult).
auto iterator_result_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( iterator_result_register ) ;
generator . emit < Bytecode : : Op : : IteratorResultDone > ( ) ;
// e. If done is true, return V.
auto & loop_continue = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets ( Bytecode : : Label { loop_end } , Bytecode : : Label { loop_continue } ) ;
generator . switch_to_basic_block ( loop_continue ) ;
// f. Let nextValue be ? IteratorValue(nextResult).
generator . emit < Bytecode : : Op : : Load > ( iterator_result_register ) ;
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
// g. If lhsKind is either assignment or varBinding, then
if ( head_result . lhs_kind ! = LHSKind : : LexicalBinding ) {
// i. If destructuring is false, then
if ( ! destructuring ) {
// 1. Let lhsRef be the result of evaluating lhs. (It may be evaluated repeatedly.)
// NOTE: We're skipping all the completion stuff that the spec does, as the unwinding mechanism will take case of doing that.
if ( head_result . lhs_kind = = LHSKind : : VarBinding ) {
2023-02-19 22:07:52 +01:00
auto & declaration = static_cast < VariableDeclaration const & > ( * lhs . get < NonnullRefPtr < ASTNode const > > ( ) ) ;
2022-03-18 20:18:19 +03:30
VERIFY ( declaration . declarations ( ) . size ( ) = = 1 ) ;
TRY ( assign_accumulator_to_variable_declarator ( generator , declaration . declarations ( ) . first ( ) , declaration ) ) ;
} else {
2023-02-19 22:07:52 +01:00
if ( auto ptr = lhs . get_pointer < NonnullRefPtr < ASTNode const > > ( ) ) {
2022-03-31 03:09:36 +04:30
TRY ( generator . emit_store_to_reference ( * * ptr ) ) ;
} else {
2023-02-19 22:07:52 +01:00
auto & binding_pattern = lhs . get < NonnullRefPtr < BindingPattern const > > ( ) ;
2022-12-09 18:47:51 +00:00
auto value_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( value_register ) ;
2023-06-24 20:29:30 +02:00
TRY ( generate_binding_pattern_bytecode ( generator , * binding_pattern , Bytecode : : Op : : SetVariable : : InitializationMode : : Set , value_register , false ) ) ;
2022-03-31 03:09:36 +04:30
}
2022-03-18 20:18:19 +03:30
}
}
}
// h. Else,
else {
// i. Assert: lhsKind is lexicalBinding.
// ii. Assert: lhs is a ForDeclaration.
// iii. Let iterationEnv be NewDeclarativeEnvironment(oldEnv).
// iv. Perform ForDeclarationBindingInstantiation of lhs with argument iterationEnv.
// v. Set the running execution context's LexicalEnvironment to iterationEnv.
2023-06-16 16:34:47 +02:00
generator . begin_variable_scope ( ) ;
2022-03-18 20:18:19 +03:30
has_lexical_binding = true ;
// 14.7.5.4 Runtime Semantics: ForDeclarationBindingInstantiation, https://tc39.es/ecma262/#sec-runtime-semantics-fordeclarationbindinginstantiation
// 1. Assert: environment is a declarative Environment Record.
// NOTE: We just made it.
2023-02-19 22:07:52 +01:00
auto & variable_declaration = static_cast < VariableDeclaration const & > ( * lhs . get < NonnullRefPtr < ASTNode const > > ( ) ) ;
2022-03-18 20:18:19 +03:30
// 2. For each element name of the BoundNames of ForBinding, do
2023-02-27 22:13:37 +00:00
// NOTE: Nothing in the callback throws an exception.
MUST ( variable_declaration . for_each_bound_name ( [ & ] ( auto const & name ) {
2022-03-18 20:18:19 +03:30
auto identifier = generator . intern_identifier ( name ) ;
// a. If IsConstantDeclaration of LetOrConst is true, then
if ( variable_declaration . is_constant_declaration ( ) ) {
// i. Perform ! environment.CreateImmutableBinding(name, true).
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , true ) ;
}
// b. Else,
else {
// i. Perform ! environment.CreateMutableBinding(name, false).
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
}
2023-02-27 22:13:37 +00:00
} ) ) ;
2022-03-18 20:18:19 +03:30
// 3. Return unused.
// NOTE: No need to do that as we've inlined this.
// vi. If destructuring is false, then
if ( ! destructuring ) {
// 1. Assert: lhs binds a single name.
// 2. Let lhsName be the sole element of BoundNames of lhs.
2023-03-06 14:17:01 +01:00
auto lhs_name = variable_declaration . declarations ( ) . first ( ) - > target ( ) . get < NonnullRefPtr < Identifier const > > ( ) - > string ( ) ;
2022-03-18 20:18:19 +03:30
// 3. Let lhsRef be ! ResolveBinding(lhsName).
// NOTE: We're skipping all the completion stuff that the spec does, as the unwinding mechanism will take case of doing that.
auto identifier = generator . intern_identifier ( lhs_name ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( identifier , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , Bytecode : : Op : : EnvironmentMode : : Lexical ) ;
}
}
// i. If destructuring is false, then
if ( ! destructuring ) {
// i. If lhsRef is an abrupt completion, then
// 1. Let status be lhsRef.
// ii. Else if lhsKind is lexicalBinding, then
// 1. Let status be Completion(InitializeReferencedBinding(lhsRef, nextValue)).
// iii. Else,
// 1. Let status be Completion(PutValue(lhsRef, nextValue)).
// NOTE: This is performed above.
}
// j. Else,
else {
2022-12-09 18:47:51 +00:00
// FIXME: i. If lhsKind is assignment, then
// 1. Let status be Completion(DestructuringAssignmentEvaluation of assignmentPattern with argument nextValue).
2022-03-18 20:18:19 +03:30
// ii. Else if lhsKind is varBinding, then
// 1. Assert: lhs is a ForBinding.
// 2. Let status be Completion(BindingInitialization of lhs with arguments nextValue and undefined).
// iii. Else,
// 1. Assert: lhsKind is lexicalBinding.
// 2. Assert: lhs is a ForDeclaration.
// 3. Let status be Completion(ForDeclarationBindingInitialization of lhs with arguments nextValue and iterationEnv).
2022-12-09 18:47:51 +00:00
if ( head_result . lhs_kind = = LHSKind : : VarBinding | | head_result . lhs_kind = = LHSKind : : LexicalBinding ) {
2023-02-19 22:07:52 +01:00
auto & declaration = static_cast < VariableDeclaration const & > ( * lhs . get < NonnullRefPtr < ASTNode const > > ( ) ) ;
2022-12-09 18:47:51 +00:00
VERIFY ( declaration . declarations ( ) . size ( ) = = 1 ) ;
2023-03-06 14:17:01 +01:00
auto & binding_pattern = declaration . declarations ( ) . first ( ) - > target ( ) . get < NonnullRefPtr < BindingPattern const > > ( ) ;
2022-12-09 18:47:51 +00:00
auto value_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( value_register ) ;
2023-06-24 20:29:30 +02:00
TRY ( generate_binding_pattern_bytecode ( generator , * binding_pattern , head_result . lhs_kind = = LHSKind : : VarBinding ? Bytecode : : Op : : SetVariable : : InitializationMode : : Set : Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , value_register , false ) ) ;
2022-12-09 18:47:51 +00:00
} else {
return Bytecode : : CodeGenerationError {
& node ,
" Unimplemented: assignment destructuring in for/of " sv ,
} ;
}
2022-03-18 20:18:19 +03:30
}
// FIXME: Implement iteration closure.
// k. If status is an abrupt completion, then
// i. Set the running execution context's LexicalEnvironment to oldEnv.
// ii. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
// iii. If iterationKind is enumerate, then
// 1. Return ? status.
// iv. Else,
// 1. Assert: iterationKind is iterate.
// 2. Return ? IteratorClose(iteratorRecord, status).
// l. Let result be the result of evaluating stmt.
TRY ( body . generate_bytecode ( generator ) ) ;
// m. Set the running execution context's LexicalEnvironment to oldEnv.
if ( has_lexical_binding )
generator . end_variable_scope ( ) ;
generator . end_continuable_scope ( ) ;
generator . end_breakable_scope ( ) ;
// NOTE: If we're here, then the loop definitely continues.
// n. If LoopContinues(result, labelSet) is false, then
// i. If iterationKind is enumerate, then
// 1. Return ? UpdateEmpty(result, V).
// ii. Else,
// 1. Assert: iterationKind is iterate.
// 2. Set status to Completion(UpdateEmpty(result, V)).
// 3. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
// 4. Return ? IteratorClose(iteratorRecord, status).
// o. If result.[[Value]] is not empty, set V to result.[[Value]].
2022-03-27 18:46:25 +01:00
// The body can contain an unconditional block terminator (e.g. return, throw), so we have to check for that before generating the Jump.
if ( ! generator . is_current_block_terminated ( ) )
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { loop_update } , { } ) ;
2022-03-18 20:18:19 +03:30
generator . switch_to_basic_block ( loop_end ) ;
return { } ;
}
Bytecode : : CodeGenerationErrorOr < void > ForInStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
// 14.7.5.5 Runtime Semantics: ForInOfLoopEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-forinofloopevaluation
2023-01-08 19:23:00 -05:00
Bytecode : : CodeGenerationErrorOr < void > ForInStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set ) const
2022-03-18 20:18:19 +03:30
{
auto & loop_end = generator . make_block ( ) ;
auto & loop_update = generator . make_block ( ) ;
2022-06-11 23:09:37 +01:00
generator . begin_breakable_scope ( Bytecode : : Label { loop_end } , label_set ) ;
2022-03-18 20:18:19 +03:30
auto head_result = TRY ( for_in_of_head_evaluation ( generator , IterationKind : : Enumerate , m_lhs , m_rhs ) ) ;
// Now perform the rest of ForInOfLoopEvaluation, given that the accumulator holds the iterator we're supposed to iterate over.
2022-06-11 23:09:37 +01:00
return for_in_of_body_evaluation ( generator , * this , m_lhs , body ( ) , head_result , label_set , loop_end , loop_update ) ;
2022-03-18 20:18:19 +03:30
}
Bytecode : : CodeGenerationErrorOr < void > ForOfStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
2023-01-08 19:23:00 -05:00
Bytecode : : CodeGenerationErrorOr < void > ForOfStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set ) const
2022-03-18 20:18:19 +03:30
{
auto & loop_end = generator . make_block ( ) ;
auto & loop_update = generator . make_block ( ) ;
2022-06-11 23:09:37 +01:00
generator . begin_breakable_scope ( Bytecode : : Label { loop_end } , label_set ) ;
2022-03-18 20:18:19 +03:30
auto head_result = TRY ( for_in_of_head_evaluation ( generator , IterationKind : : Iterate , m_lhs , m_rhs ) ) ;
// Now perform the rest of ForInOfLoopEvaluation, given that the accumulator holds the iterator we're supposed to iterate over.
2022-06-11 23:09:37 +01:00
return for_in_of_body_evaluation ( generator , * this , m_lhs , body ( ) , head_result , label_set , loop_end , loop_update ) ;
2022-03-18 20:18:19 +03:30
}
2023-06-27 19:24:34 +01:00
Bytecode : : CodeGenerationErrorOr < void > ForAwaitOfStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
return generate_labelled_evaluation ( generator , { } ) ;
}
Bytecode : : CodeGenerationErrorOr < void > ForAwaitOfStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set ) const
{
auto & loop_end = generator . make_block ( ) ;
auto & loop_update = generator . make_block ( ) ;
generator . begin_breakable_scope ( Bytecode : : Label { loop_end } , label_set ) ;
auto head_result = TRY ( for_in_of_head_evaluation ( generator , IterationKind : : AsyncIterate , m_lhs , m_rhs ) ) ;
// Now perform the rest of ForInOfLoopEvaluation, given that the accumulator holds the iterator we're supposed to iterate over.
return for_in_of_body_evaluation ( generator , * this , m_lhs , m_body , head_result , label_set , loop_end , loop_update , IteratorHint : : Async ) ;
}
2022-03-19 19:40:21 +00:00
// 13.3.12.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation
Bytecode : : CodeGenerationErrorOr < void > MetaProperty : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
// NewTarget : new . target
if ( m_type = = MetaProperty : : Type : : NewTarget ) {
// 1. Return GetNewTarget().
generator . emit < Bytecode : : Op : : GetNewTarget > ( ) ;
return { } ;
}
// ImportMeta : import . meta
if ( m_type = = MetaProperty : : Type : : ImportMeta ) {
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented meta property: import.meta " sv ,
} ;
}
VERIFY_NOT_REACHED ( ) ;
}
2023-06-17 10:11:23 +02:00
Bytecode : : CodeGenerationErrorOr < void > ClassFieldInitializerStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
2023-06-23 14:27:42 +02:00
TRY ( generator . emit_named_evaluation_if_anonymous_function ( * m_expression , m_class_field_identifier_name ) ) ;
2023-06-17 10:11:23 +02:00
generator . perform_needed_unwinds < Bytecode : : Op : : Return > ( ) ;
generator . emit < Bytecode : : Op : : Return > ( ) ;
return { } ;
}
2023-06-17 14:50:23 +01:00
static Bytecode : : CodeGenerationErrorOr < void > generate_optional_chain ( Bytecode : : Generator & generator , OptionalChain const & optional_chain , Bytecode : : Register current_value_register , Bytecode : : Register current_base_register )
{
if ( is < MemberExpression > ( optional_chain . base ( ) ) ) {
auto & member_expression = static_cast < MemberExpression const & > ( optional_chain . base ( ) ) ;
TRY ( get_base_and_value_from_member_expression ( generator , member_expression , current_base_register ) ) ;
} else if ( is < OptionalChain > ( optional_chain . base ( ) ) ) {
auto & sub_optional_chain = static_cast < OptionalChain const & > ( optional_chain . base ( ) ) ;
TRY ( generate_optional_chain ( generator , sub_optional_chain , current_value_register , current_base_register ) ) ;
} else {
TRY ( optional_chain . base ( ) . generate_bytecode ( generator ) ) ;
}
generator . emit < Bytecode : : Op : : Store > ( current_value_register ) ;
auto & load_undefined_and_jump_to_end_block = generator . make_block ( ) ;
auto & end_block = generator . make_block ( ) ;
for ( auto & reference : optional_chain . references ( ) ) {
auto is_optional = reference . visit ( [ ] ( auto & ref ) { return ref . mode ; } ) = = OptionalChain : : Mode : : Optional ;
if ( is_optional ) {
auto & not_nullish_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpNullish > (
Bytecode : : Label { load_undefined_and_jump_to_end_block } ,
Bytecode : : Label { not_nullish_block } ) ;
generator . switch_to_basic_block ( not_nullish_block ) ;
}
TRY ( reference . visit (
[ & ] ( OptionalChain : : Call const & call ) - > Bytecode : : CodeGenerationErrorOr < void > {
TRY ( arguments_to_array_for_call ( generator , call . arguments ) ) ;
generator . emit < Bytecode : : Op : : Call > ( Bytecode : : Op : : Call : : CallType : : Call , current_value_register , current_base_register ) ;
generator . emit < Bytecode : : Op : : Store > ( current_value_register ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Store > ( current_base_register ) ;
generator . emit < Bytecode : : Op : : Load > ( current_value_register ) ;
return { } ;
} ,
[ & ] ( OptionalChain : : ComputedReference const & ref ) - > Bytecode : : CodeGenerationErrorOr < void > {
generator . emit < Bytecode : : Op : : Store > ( current_base_register ) ;
TRY ( ref . expression - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : GetByValue > ( current_base_register ) ;
generator . emit < Bytecode : : Op : : Store > ( current_value_register ) ;
return { } ;
} ,
[ & ] ( OptionalChain : : MemberReference const & ref ) - > Bytecode : : CodeGenerationErrorOr < void > {
generator . emit < Bytecode : : Op : : Store > ( current_base_register ) ;
generator . emit < Bytecode : : Op : : GetById > ( generator . intern_identifier ( ref . identifier - > string ( ) ) ) ;
generator . emit < Bytecode : : Op : : Store > ( current_value_register ) ;
return { } ;
} ,
2023-06-23 19:09:41 +01:00
[ & ] ( OptionalChain : : PrivateMemberReference const & ref ) - > Bytecode : : CodeGenerationErrorOr < void > {
generator . emit < Bytecode : : Op : : Store > ( current_base_register ) ;
generator . emit < Bytecode : : Op : : GetPrivateById > ( generator . intern_identifier ( ref . private_identifier - > string ( ) ) ) ;
generator . emit < Bytecode : : Op : : Store > ( current_value_register ) ;
return { } ;
2023-06-17 14:50:23 +01:00
} ) ) ;
}
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
generator . switch_to_basic_block ( load_undefined_and_jump_to_end_block ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
generator . switch_to_basic_block ( end_block ) ;
return { } ;
}
Bytecode : : CodeGenerationErrorOr < void > OptionalChain : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
auto current_base_register = generator . allocate_register ( ) ;
auto current_value_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Store > ( current_base_register ) ;
return generate_optional_chain ( generator , * this , current_value_register , current_base_register ) ;
}
2023-06-24 15:22:16 +02:00
Bytecode : : CodeGenerationErrorOr < void > ImportCall : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
TRY ( m_specifier - > generate_bytecode ( generator ) ) ;
auto specifier_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( specifier_reg ) ;
if ( m_options ) {
TRY ( m_options - > generate_bytecode ( generator ) ) ;
} else {
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
}
auto options_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( options_reg ) ;
generator . emit < Bytecode : : Op : : ImportCall > ( specifier_reg , options_reg ) ;
return { } ;
}
2023-06-24 16:07:43 +02:00
Bytecode : : CodeGenerationErrorOr < void > ExportStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
if ( ! is_default_export ( ) ) {
if ( m_statement ) {
return m_statement - > generate_bytecode ( generator ) ;
}
return { } ;
}
VERIFY ( m_statement ) ;
if ( is < FunctionDeclaration > ( * m_statement ) | | is < ClassDeclaration > ( * m_statement ) ) {
return m_statement - > generate_bytecode ( generator ) ;
}
if ( is < ClassExpression > ( * m_statement ) ) {
TODO ( ) ;
}
// ExportDeclaration : export default AssignmentExpression ;
VERIFY ( is < Expression > ( * m_statement ) ) ;
TRY ( generator . emit_named_evaluation_if_anonymous_function ( static_cast < Expression const & > ( * m_statement ) , DeprecatedFlyString ( " default " sv ) ) ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( " default " sv ) ) ;
return { } ;
}
2023-06-27 20:46:41 +02:00
Bytecode : : CodeGenerationErrorOr < void > ImportStatement : : generate_bytecode ( Bytecode : : Generator & ) const
{
return { } ;
}
2021-06-04 11:31:13 +02:00
}