2021-06-04 11:31:13 +02:00
/*
2024-02-03 20:16:02 +01:00
* Copyright ( c ) 2021 - 2024 , 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>
2024-05-08 13:08:38 +02:00
# include <AK/Queue.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 {
2024-05-07 21:36:56 +02:00
using namespace JS : : Bytecode ;
static ScopedOperand choose_dst ( Bytecode : : Generator & generator , Optional < ScopedOperand > const & preferred_dst )
2024-02-04 08:00:54 +01:00
{
if ( preferred_dst . has_value ( ) )
return preferred_dst . value ( ) ;
2024-05-07 21:36:56 +02:00
return generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ASTNode : : generate_bytecode ( Bytecode : : Generator & , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) 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
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ScopeNode : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-04 11:31:13 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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 ( ) ) {
2024-05-11 13:25:08 +02:00
did_create_lexical_environment = generator . emit_block_declaration_instantiation ( * this ) ;
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
}
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > last_result ;
2021-06-09 19:57:18 +02:00
for ( auto & child : children ( ) ) {
2024-02-04 08:00:54 +01:00
auto result = TRY ( child - > generate_bytecode ( generator ) ) ;
if ( result . has_value ( ) )
last_result = result ;
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 ( ) ;
2024-02-04 08:00:54 +01:00
return last_result ;
2021-06-04 11:31:13 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > EmptyStatement : : generate_bytecode ( Bytecode : : Generator & , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-07 20:47:26 +02:00
{
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2021-06-07 20:47:26 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ExpressionStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-04 11:31:13 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-02-12 19:54:08 +03:30
return m_expression - > generate_bytecode ( generator ) ;
2021-06-04 11:31:13 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > BinaryExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-04 11:31:13 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2023-07-05 12:42:50 +02:00
if ( m_op = = BinaryOp : : In & & is < PrivateIdentifier > ( * m_lhs ) ) {
auto const & private_identifier = static_cast < PrivateIdentifier const & > ( * m_lhs ) . string ( ) ;
2024-02-04 08:00:54 +01:00
auto base = TRY ( m_rhs - > generate_bytecode ( generator ) ) . value ( ) ;
auto dst = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : HasPrivateId > ( dst , base , generator . intern_identifier ( private_identifier ) ) ;
return dst ;
2023-07-05 12:42:50 +02:00
}
2024-05-09 15:17:34 +02:00
// OPTIMIZATION: If LHS and/or RHS are numeric literals, we make sure they are converted to i32/u32
// as appropriate, to avoid having to perform these conversions at runtime.
2021-06-04 11:31:13 +02:00
2024-05-09 15:17:34 +02:00
auto get_left_side = [ & ] ( Expression const & side ) - > CodeGenerationErrorOr < Optional < ScopedOperand > > {
switch ( m_op ) {
case BinaryOp : : BitwiseAnd :
case BinaryOp : : BitwiseOr :
case BinaryOp : : BitwiseXor :
case BinaryOp : : LeftShift :
case BinaryOp : : RightShift :
case BinaryOp : : UnsignedRightShift :
// LHS will always be converted to i32 for these ops.
if ( side . is_numeric_literal ( ) ) {
auto value = MUST ( static_cast < NumericLiteral const & > ( side ) . value ( ) . to_i32 ( generator . vm ( ) ) ) ;
return generator . add_constant ( Value ( value ) ) ;
}
break ;
default :
break ;
}
return side . generate_bytecode ( generator ) ;
} ;
auto get_right_side = [ & ] ( Expression const & side ) - > CodeGenerationErrorOr < Optional < ScopedOperand > > {
switch ( m_op ) {
case BinaryOp : : BitwiseAnd :
case BinaryOp : : BitwiseOr :
case BinaryOp : : BitwiseXor :
// RHS will always be converted to i32 for these ops.
if ( side . is_numeric_literal ( ) ) {
auto value = MUST ( static_cast < NumericLiteral const & > ( side ) . value ( ) . to_i32 ( generator . vm ( ) ) ) ;
return generator . add_constant ( Value ( value ) ) ;
}
break ;
case BinaryOp : : LeftShift :
case BinaryOp : : RightShift :
case BinaryOp : : UnsignedRightShift :
// RHS will always be converted to u32 for these ops.
if ( side . is_numeric_literal ( ) ) {
auto value = MUST ( static_cast < NumericLiteral const & > ( side ) . value ( ) . to_u32 ( generator . vm ( ) ) ) ;
return generator . add_constant ( Value ( value ) ) ;
}
break ;
default :
break ;
}
return side . generate_bytecode ( generator ) ;
} ;
auto lhs = TRY ( get_left_side ( * m_lhs ) ) . value ( ) ;
auto rhs = TRY ( get_right_side ( * m_rhs ) ) . value ( ) ;
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
2021-06-04 11:31:13 +02:00
switch ( m_op ) {
case BinaryOp : : Addition :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Add > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-04 11:31:13 +02:00
case BinaryOp : : Subtraction :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Sub > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:17:20 +02:00
case BinaryOp : : Multiplication :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mul > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:17:20 +02:00
case BinaryOp : : Division :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Div > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:37:23 +02:00
case BinaryOp : : Modulo :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mod > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:37:23 +02:00
case BinaryOp : : Exponentiation :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Exp > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:57:38 +02:00
case BinaryOp : : GreaterThan :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GreaterThan > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:57:38 +02:00
case BinaryOp : : GreaterThanEquals :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GreaterThanEquals > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-04 12:03:57 +02:00
case BinaryOp : : LessThan :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : LessThan > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:57:38 +02:00
case BinaryOp : : LessThanEquals :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : LessThanEquals > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : LooselyInequals :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : LooselyInequals > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : LooselyEquals :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : LooselyEquals > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : StrictlyInequals :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyInequals > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : StrictlyEquals :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyEquals > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:16:04 +01:00
case BinaryOp : : BitwiseAnd :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : BitwiseAnd > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:16:04 +01:00
case BinaryOp : : BitwiseOr :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : BitwiseOr > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:16:04 +01:00
case BinaryOp : : BitwiseXor :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : BitwiseXor > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 20:14:12 +01:00
case BinaryOp : : LeftShift :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : LeftShift > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 20:14:12 +01:00
case BinaryOp : : RightShift :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : RightShift > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 20:14:12 +01:00
case BinaryOp : : UnsignedRightShift :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : UnsignedRightShift > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 21:13:37 +01:00
case BinaryOp : : In :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : In > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 21:18:19 +01:00
case BinaryOp : : InstanceOf :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : InstanceOf > ( dst , lhs , rhs ) ;
2021-06-07 20:58:36 -07:00
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
}
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-04 11:31:13 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > LogicalExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-08 02:18:47 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
auto lhs = TRY ( m_lhs - > generate_bytecode ( generator , preferred_dst ) ) . value ( ) ;
// FIXME: Only mov lhs into dst in case lhs is the value taken.
generator . emit < Bytecode : : Op : : Mov > ( dst , lhs ) ;
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 :
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
lhs ,
2021-06-09 06:49:58 +04:30
Bytecode : : Label { rhs_block } ,
Bytecode : : Label { end_block } ) ;
2021-06-08 02:18:47 +02:00
break ;
case LogicalOp : : Or :
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
lhs ,
2021-06-09 06:49:58 +04:30
Bytecode : : Label { end_block } ,
Bytecode : : Label { rhs_block } ) ;
2021-06-08 02:18:47 +02:00
break ;
case LogicalOp : : NullishCoalescing :
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : JumpNullish > (
2024-02-04 08:00:54 +01:00
lhs ,
2021-06-09 06:49:58 +04:30
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 ) ;
2024-02-04 08:00:54 +01:00
auto rhs = TRY ( m_rhs - > generate_bytecode ( generator ) ) . value ( ) ;
2021-06-09 06:49:58 +04:30
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( dst , rhs ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( end_block ) ;
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-08 02:18:47 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > UnaryExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-07 19:53:47 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-05-09 19:48:25 +02:00
// OPTIMIZATION: Turn expressions like `-1` into a constant.
if ( m_op = = UnaryOp : : Minus & & is < NumericLiteral > ( * m_lhs ) ) {
auto & numeric_literal = static_cast < NumericLiteral const & > ( * m_lhs ) ;
auto value = numeric_literal . value ( ) ;
return generator . add_constant ( Value ( - value . as_double ( ) ) ) ;
}
2022-03-27 19:50:09 +01:00
if ( m_op = = UnaryOp : : Delete )
return generator . emit_delete_reference ( m_lhs ) ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > src ;
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 )
2024-02-04 08:00:54 +01:00
src = TRY ( m_lhs - > generate_bytecode ( generator ) ) . value ( ) ;
auto dst = choose_dst ( generator , preferred_dst ) ;
2021-06-07 19:53:47 +01:00
switch ( m_op ) {
case UnaryOp : : BitwiseNot :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : BitwiseNot > ( dst , * src ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Not :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Not > ( dst , * src ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Plus :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : UnaryPlus > ( dst , * src ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Minus :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : UnaryMinus > ( dst , * src ) ;
2021-06-07 20:58:36 -07:00
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 ) ;
2024-02-04 08:00:54 +01:00
if ( ! identifier . is_local ( ) ) {
generator . emit < Bytecode : : Op : : TypeofVariable > ( dst , generator . intern_identifier ( identifier . string ( ) ) ) ;
break ;
2023-07-05 02:17:10 +02:00
}
2022-06-11 23:12:22 +01:00
}
2024-02-04 08:00:54 +01:00
src = TRY ( m_lhs - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : Typeof > ( dst , * src ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Void :
2024-02-04 08:00:54 +01:00
return generator . add_constant ( js_undefined ( ) ) ;
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
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-07 19:53:47 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > NumericLiteral : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-04 11:31:13 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
return generator . add_constant ( Value ( m_value ) , Bytecode : : Generator : : DeduplicateConstant : : No ) ;
2021-06-04 11:31:13 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > BooleanLiteral : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-07 20:22:15 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
return generator . add_constant ( Value ( m_value ) ) ;
2021-06-07 20:22:15 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > NullLiteral : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-07 20:22:15 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
return generator . add_constant ( js_null ( ) ) ;
2021-06-07 20:22:15 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > BigIntLiteral : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-08 07:59:25 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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 ' )
2024-01-12 21:34:23 +00:00
return MUST ( Crypto : : SignedBigInteger : : from_base ( 16 , m_value . substring ( 2 , m_value . length ( ) - 3 ) ) ) ;
2022-10-19 19:17:58 +02:00
if ( m_value [ 1 ] = = ' o ' | | m_value [ 1 ] = = ' O ' )
2024-01-12 21:34:23 +00:00
return MUST ( Crypto : : SignedBigInteger : : from_base ( 8 , m_value . substring ( 2 , m_value . length ( ) - 3 ) ) ) ;
2022-10-19 19:17:58 +02:00
if ( m_value [ 1 ] = = ' b ' | | m_value [ 1 ] = = ' B ' )
2024-01-12 21:34:23 +00:00
return MUST ( Crypto : : SignedBigInteger : : from_base ( 2 , m_value . substring ( 2 , m_value . length ( ) - 3 ) ) ) ;
return MUST ( Crypto : : SignedBigInteger : : from_base ( 10 , m_value . substring ( 0 , m_value . length ( ) - 1 ) ) ) ;
2022-10-19 19:17:58 +02:00
} ( ) ;
2024-03-03 11:40:00 +01:00
return generator . add_constant ( BigInt : : create ( generator . vm ( ) , move ( integer ) ) , Bytecode : : Generator : : DeduplicateConstant : : No ) ;
2021-06-08 07:59:25 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > StringLiteral : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-04 11:31:13 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-03-03 11:34:36 +01:00
return generator . add_constant ( PrimitiveString : : create ( generator . vm ( ) , m_value ) , Bytecode : : Generator : : DeduplicateConstant : : No ) ;
2021-06-04 11:31:13 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > RegExpLiteral : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-19 17:17:40 -07:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2021-06-19 17:17:40 -07:00
auto source_index = generator . intern_string ( m_pattern ) ;
auto flags_index = generator . intern_string ( m_flags ) ;
2023-07-13 10:49:07 +02:00
auto regex_index = generator . intern_regex ( Bytecode : : ParsedRegex {
. regex = m_parsed_regex ,
. pattern = m_parsed_pattern ,
. flags = m_parsed_flags ,
} ) ;
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : NewRegExp > ( dst , source_index , flags_index , regex_index ) ;
return dst ;
2021-06-19 17:17:40 -07:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > Identifier : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-04 11:31:13 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
if ( is_local ( ) ) {
2024-05-07 21:36:56 +02:00
auto local = generator . local ( local_variable_index ( ) ) ;
2024-02-04 08:00:54 +01:00
if ( ! generator . is_local_initialized ( local_variable_index ( ) ) ) {
generator . emit < Bytecode : : Op : : ThrowIfTDZ > ( local ) ;
}
return local ;
}
2024-05-09 15:21:24 +02:00
if ( is_global ( ) & & m_string = = " undefined " sv ) {
return generator . add_constant ( js_undefined ( ) ) ;
}
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
2023-07-12 04:06:59 +02:00
if ( is_global ( ) ) {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetGlobal > ( dst , generator . intern_identifier ( m_string ) , generator . next_global_variable_cache ( ) ) ;
2023-07-05 02:17:10 +02:00
} else {
2024-05-11 18:28:03 +02:00
generator . emit < Bytecode : : Op : : GetVariable > ( dst , generator . intern_identifier ( m_string ) ) ;
2023-07-05 02:17:10 +02:00
}
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-04 11:31:13 +02:00
}
2024-05-07 21:36:56 +02:00
static Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > arguments_to_array_for_call ( Bytecode : : Generator & generator , ReadonlySpan < CallExpression : : Argument > arguments )
2022-09-09 16:05:40 +02:00
{
2024-05-07 21:36:56 +02:00
auto dst = generator . allocate_register ( ) ;
2022-09-09 16:05:40 +02:00
if ( arguments . is_empty ( ) ) {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : NewArray > ( dst ) ;
return dst ;
2022-09-09 16:05:40 +02:00
}
auto first_spread = find_if ( arguments . begin ( ) , arguments . end ( ) , [ ] ( auto el ) { return el . is_spread ; } ) ;
2024-05-08 12:43:08 +02:00
Vector < ScopedOperand > args ;
args . ensure_capacity ( first_spread . index ( ) ) ;
2022-09-09 16:05:40 +02:00
for ( auto it = arguments . begin ( ) ; it ! = first_spread ; + + it ) {
2024-05-08 12:43:08 +02:00
VERIFY ( ! it - > is_spread ) ;
auto reg = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
auto value = TRY ( it - > value - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-08 12:43:08 +02:00
generator . emit < Bytecode : : Op : : Mov > ( reg , value ) ;
args . append ( move ( reg ) ) ;
2022-09-09 16:05:40 +02:00
}
if ( first_spread . index ( ) ! = 0 )
2024-05-08 12:43:08 +02:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : NewArray > ( args . size ( ) , dst , args ) ;
2022-09-09 16:05:40 +02:00
else
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : NewArray > ( dst ) ;
2022-09-09 16:05:40 +02:00
if ( first_spread ! = arguments . end ( ) ) {
for ( auto it = first_spread ; it ! = arguments . end ( ) ; + + it ) {
2024-02-04 08:00:54 +01:00
auto value = TRY ( it - > value - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : ArrayAppend > ( dst , value , it - > is_spread ) ;
2022-09-09 16:05:40 +02:00
}
}
2024-02-04 08:00:54 +01:00
return dst ;
2022-09-09 16:05:40 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > SuperCall : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2022-08-30 18:03:02 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > arguments ;
2022-08-30 18:03:02 +02:00
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 ] ;
2024-02-04 08:00:54 +01:00
// This generates a single argument.
arguments = MUST ( argument . value - > generate_bytecode ( generator ) ) ;
2022-08-30 18:03:02 +02:00
} else {
2024-02-04 08:00:54 +01:00
arguments = TRY ( arguments_to_array_for_call ( generator , m_arguments ) ) . value ( ) ;
2022-08-30 18:03:02 +02:00
}
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : SuperCallWithArgumentArray > ( dst , * arguments , m_is_synthetic = = IsPartOfSyntheticConstructor : : Yes ) ;
return dst ;
2022-08-30 18:03:02 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > AssignmentExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-04 11:31:13 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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
2024-05-07 21:36:56 +02:00
[ & ] ( NonnullRefPtr < Expression const > const & lhs ) - > Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > {
2022-07-17 19:23:52 +01:00
// a. Let lref be the result of evaluating LeftHandSideExpression.
// b. ReturnIfAbrupt(lref).
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > base ;
Optional < ScopedOperand > computed_property ;
Optional < ScopedOperand > this_value ;
2023-07-02 19:26:31 +01:00
bool lhs_is_super_expression = false ;
2022-07-17 19:23:52 +01:00
if ( is < MemberExpression > ( * lhs ) ) {
auto & expression = static_cast < MemberExpression const & > ( * lhs ) ;
2023-07-02 19:26:31 +01:00
lhs_is_super_expression = is < SuperExpression > ( expression . object ( ) ) ;
if ( ! lhs_is_super_expression ) {
2024-02-04 08:00:54 +01:00
base = TRY ( expression . object ( ) . generate_bytecode ( generator ) ) . value ( ) ;
2023-07-02 19:26:31 +01:00
} else {
// https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
// 1. Let env be GetThisEnvironment().
// 2. Let actualThis be ? env.GetThisBinding().
2024-05-07 12:16:37 +02:00
this_value = generator . get_this ( ) ;
2023-07-02 19:26:31 +01:00
// SuperProperty : super [ Expression ]
// 3. Let propertyNameReference be ? Evaluation of Expression.
// 4. Let propertyNameValue be ? GetValue(propertyNameReference).
}
2022-07-17 19:23:52 +01:00
if ( expression . is_computed ( ) ) {
2024-03-05 09:48:13 +01:00
auto property = TRY ( expression . property ( ) . generate_bytecode ( generator ) ) . value ( ) ;
2024-05-07 21:36:56 +02:00
computed_property = generator . allocate_register ( ) ;
2024-03-05 09:48:13 +01:00
generator . emit < Bytecode : : Op : : Mov > ( * computed_property , property ) ;
2022-07-17 19:23:52 +01:00
// 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
} ;
}
2023-07-02 19:26:31 +01:00
if ( lhs_is_super_expression ) {
// 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().
// 4. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }.
2024-05-07 21:36:56 +02:00
base = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ResolveSuperBase > ( * base ) ;
2023-07-02 19:26:31 +01:00
}
2022-07-17 19:23:52 +01:00
} 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 {
2024-02-04 08:00:54 +01:00
( void ) TRY ( lhs - > generate_bytecode ( generator ) ) ;
2022-07-17 19:23:52 +01:00
}
// 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).
2024-05-07 21:36:56 +02:00
auto rval = TRY ( [ & ] ( ) - > Bytecode : : CodeGenerationErrorOr < ScopedOperand > {
2024-02-04 08:00:54 +01:00
if ( lhs - > is_identifier ( ) ) {
return TRY ( generator . emit_named_evaluation_if_anonymous_function ( * m_rhs , generator . intern_identifier ( static_cast < Identifier const & > ( * lhs ) . string ( ) ) ) ) . value ( ) ;
} else {
return TRY ( m_rhs - > generate_bytecode ( generator ) ) . value ( ) ;
}
} ( ) ) ;
2022-07-17 19:23:52 +01:00
// e. Perform ? PutValue(lref, rval).
if ( is < Identifier > ( * lhs ) ) {
auto & identifier = static_cast < Identifier const & > ( * lhs ) ;
2024-02-04 08:00:54 +01:00
generator . emit_set_variable ( identifier , rval ) ;
2022-07-17 19:23:52 +01:00
} else if ( is < MemberExpression > ( * lhs ) ) {
auto & expression = static_cast < MemberExpression const & > ( * lhs ) ;
2024-03-29 12:10:52 -04:00
auto base_identifier = generator . intern_identifier_for_expression ( expression . object ( ) ) ;
2022-07-17 19:23:52 +01:00
if ( expression . is_computed ( ) ) {
2023-07-02 19:26:31 +01:00
if ( ! lhs_is_super_expression )
2024-03-29 12:10:52 -04:00
generator . emit < Bytecode : : Op : : PutByValue > ( * base , * computed_property , rval , Bytecode : : Op : : PropertyKind : : KeyValue , move ( base_identifier ) ) ;
2023-07-02 19:26:31 +01:00
else
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : PutByValueWithThis > ( * base , * computed_property , * this_value , rval ) ;
2022-07-17 19:23:52 +01:00
} else if ( expression . property ( ) . is_identifier ( ) ) {
auto identifier_table_ref = generator . intern_identifier ( verify_cast < Identifier > ( expression . property ( ) ) . string ( ) ) ;
2023-07-02 19:26:31 +01:00
if ( ! lhs_is_super_expression )
2024-03-29 12:10:52 -04:00
generator . emit < Bytecode : : Op : : PutById > ( * base , identifier_table_ref , rval , Bytecode : : Op : : PropertyKind : : KeyValue , generator . next_property_lookup_cache ( ) , move ( base_identifier ) ) ;
2023-07-02 19:26:31 +01:00
else
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : PutByIdWithThis > ( * base , * this_value , identifier_table_ref , rval , Bytecode : : Op : : PropertyKind : : KeyValue , generator . next_property_lookup_cache ( ) ) ;
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 ( ) ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : PutPrivateById > ( * base , identifier_table_ref , rval ) ;
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.
2024-02-04 08:00:54 +01:00
return rval ;
2022-07-17 19:23:52 +01:00
} ,
// 2. Let assignmentPattern be the AssignmentPattern that is covered by LeftHandSideExpression.
2024-05-07 21:36:56 +02:00
[ & ] ( NonnullRefPtr < BindingPattern const > const & pattern ) - > Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > {
2022-07-17 19:24:37 +01:00
// 3. Let rref be the result of evaluating AssignmentExpression.
// 4. Let rval be ? GetValue(rref).
2024-02-04 08:00:54 +01:00
auto rval = TRY ( m_rhs - > generate_bytecode ( generator ) ) . value ( ) ;
2022-07-17 19:24:37 +01:00
// 5. Perform ? DestructuringAssignmentEvaluation of assignmentPattern with argument rval.
2024-05-09 05:00:07 +00:00
TRY ( pattern - > generate_bytecode ( generator , Bytecode : : Op : : SetVariable : : InitializationMode : : Set , rval , false ) ) ;
2022-07-17 19:24:37 +01:00
// 6. Return rval.
2024-02-04 08:00:54 +01:00
return rval ;
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 > > ( ) ) ;
2024-02-04 08:00:54 +01:00
auto & lhs_expression = m_lhs . get < NonnullRefPtr < Expression const > > ( ) ;
2022-07-17 19:23:52 +01:00
2024-02-04 08:00:54 +01:00
auto reference_operands = TRY ( generator . emit_load_from_reference ( lhs_expression ) ) ;
auto lhs = reference_operands . loaded_value . value ( ) ;
2021-06-07 20:12:38 +01:00
2021-10-25 15:29:52 +02:00
Bytecode : : BasicBlock * rhs_block_ptr { nullptr } ;
2024-02-04 08:00:54 +01:00
Bytecode : : BasicBlock * lhs_block_ptr { nullptr } ;
2021-10-25 15:29:52 +02:00
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 ( ) ;
2024-02-04 08:00:54 +01:00
lhs_block_ptr = & generator . make_block ( ) ;
2021-10-25 15:29:52 +02:00
end_block_ptr = & generator . make_block ( ) ;
2021-06-09 21:14:31 +01:00
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
lhs ,
2021-10-25 15:29:52 +02:00
Bytecode : : Label { * rhs_block_ptr } ,
2024-02-04 08:00:54 +01:00
Bytecode : : Label { * lhs_block_ptr } ) ;
2021-10-25 15:29:52 +02:00
} else if ( m_op = = AssignmentOp : : OrAssignment ) { // ||=
rhs_block_ptr = & generator . make_block ( ) ;
2024-02-04 08:00:54 +01:00
lhs_block_ptr = & generator . make_block ( ) ;
2021-10-25 15:29:52 +02:00
end_block_ptr = & generator . make_block ( ) ;
2021-06-09 21:14:31 +01:00
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
lhs ,
Bytecode : : Label { * lhs_block_ptr } ,
2021-10-25 15:29:52 +02:00
Bytecode : : Label { * rhs_block_ptr } ) ;
} else if ( m_op = = AssignmentOp : : NullishAssignment ) { // ??=
rhs_block_ptr = & generator . make_block ( ) ;
2024-02-04 08:00:54 +01:00
lhs_block_ptr = & generator . make_block ( ) ;
2021-10-25 15:29:52 +02:00
end_block_ptr = & generator . make_block ( ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : JumpNullish > (
2024-02-04 08:00:54 +01:00
lhs ,
2021-10-25 15:29:52 +02:00
Bytecode : : Label { * rhs_block_ptr } ,
2024-02-04 08:00:54 +01:00
Bytecode : : Label { * lhs_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 ) ;
2024-05-07 21:36:56 +02:00
auto rhs = TRY ( [ & ] ( ) - > Bytecode : : CodeGenerationErrorOr < ScopedOperand > {
2024-02-04 08:00:54 +01:00
if ( lhs_expression - > is_identifier ( ) ) {
return TRY ( generator . emit_named_evaluation_if_anonymous_function ( * m_rhs , generator . intern_identifier ( static_cast < Identifier const & > ( * lhs_expression ) . string ( ) ) ) ) . value ( ) ;
}
return TRY ( m_rhs - > generate_bytecode ( generator ) ) . value ( ) ;
} ( ) ) ;
2023-06-26 15:26:46 +02:00
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
2021-10-25 15:29:52 +02:00
switch ( m_op ) {
case AssignmentOp : : AdditionAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Add > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : SubtractionAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Sub > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : MultiplicationAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mul > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : DivisionAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Div > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : ModuloAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mod > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : ExponentiationAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Exp > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : BitwiseAndAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : BitwiseAnd > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : BitwiseOrAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : BitwiseOr > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : BitwiseXorAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : BitwiseXor > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : LeftShiftAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : LeftShift > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : RightShiftAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : RightShift > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : UnsignedRightShiftAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : UnsignedRightShift > ( dst , lhs , rhs ) ;
2021-10-25 15:29:52 +02:00
break ;
case AssignmentOp : : AndAssignment :
case AssignmentOp : : OrAssignment :
case AssignmentOp : : NullishAssignment :
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( dst , rhs ) ;
break ;
2021-10-25 15:29:52 +02:00
default :
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented operation " sv ,
} ;
2021-06-04 20:47:07 +02:00
}
2024-02-04 08:00:54 +01:00
if ( lhs_expression - > is_identifier ( ) )
generator . emit_set_variable ( static_cast < Identifier const & > ( * lhs_expression ) , dst ) ;
2023-10-04 15:22:07 +02:00
else
2024-02-04 08:00:54 +01:00
( void ) TRY ( generator . emit_store_to_reference ( reference_operands , dst ) ) ;
2021-10-25 15:29:52 +02:00
2024-02-04 08:00:54 +01:00
if ( rhs_block_ptr ) {
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { * end_block_ptr } ) ;
}
if ( lhs_block_ptr ) {
generator . switch_to_basic_block ( * lhs_block_ptr ) ;
generator . emit < Bytecode : : Op : : Mov > ( dst , lhs ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { * end_block_ptr } ) ;
2024-02-04 08:00:54 +01:00
}
if ( end_block_ptr ) {
2021-10-25 15:29:52 +02:00
generator . switch_to_basic_block ( * end_block_ptr ) ;
}
2022-02-12 19:54:08 +03:30
2024-02-04 08:00:54 +01:00
return dst ;
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
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > LabelledStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-06-11 23:09:37 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-06-11 23:09:37 +01:00
// 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
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > LabelledStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-06-11 23:09:37 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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.
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > stmt_result ;
2022-06-11 23:09:37 +01:00
if ( is < IterationStatement > ( labelled_item ) ) {
auto const & iteration_statement = static_cast < IterationStatement const & > ( labelled_item ) ;
2024-02-04 08:00:54 +01:00
stmt_result = TRY ( iteration_statement . generate_labelled_evaluation ( generator , new_label_set ) ) ;
2022-06-11 23:09:37 +01:00
} else if ( is < SwitchStatement > ( labelled_item ) ) {
auto const & switch_statement = static_cast < SwitchStatement const & > ( labelled_item ) ;
2024-02-04 08:00:54 +01:00
stmt_result = TRY ( switch_statement . generate_labelled_evaluation ( generator , new_label_set ) ) ;
2022-06-11 23:09:37 +01:00
} else if ( is < LabelledStatement > ( labelled_item ) ) {
auto const & labelled_statement = static_cast < LabelledStatement const & > ( labelled_item ) ;
2024-02-04 08:00:54 +01:00
stmt_result = TRY ( labelled_statement . generate_labelled_evaluation ( generator , new_label_set ) ) ;
2022-06-11 23:09:37 +01:00
} 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 ) ;
2024-02-04 08:00:54 +01:00
stmt_result = TRY ( labelled_item . generate_bytecode ( generator ) ) ;
2022-06-11 23:09:37 +01:00
generator . end_breakable_scope ( ) ;
if ( ! generator . is_current_block_terminated ( ) ) {
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { labelled_break_block } ) ;
2022-06-11 23:09:37 +01:00
}
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).
2024-02-04 08:00:54 +01:00
return stmt_result ;
2022-06-11 23:09:37 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > IterationStatement : : generate_labelled_evaluation ( Bytecode : : Generator & , Vector < DeprecatedFlyString > const & , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-06-11 23:09:37 +01:00
{
return Bytecode : : CodeGenerationError {
this ,
" Missing generate_labelled_evaluation() " sv ,
} ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > WhileStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-06-11 23:09:37 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-06-11 23:09:37 +01:00
return generate_labelled_evaluation ( generator , { } ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > WhileStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-04 12:07:38 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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 ( ) ;
auto & end_block = generator . make_block ( ) ;
2024-05-07 21:36:56 +02:00
auto result = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( result , generator . add_constant ( js_undefined ( ) ) ) ;
2021-06-09 06:49:58 +04:30
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { test_block } ) ;
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( test_block ) ;
2024-02-04 08:00:54 +01:00
auto test = TRY ( m_test - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
test ,
2021-06-09 06:49:58 +04:30
Bytecode : : Label { body_block } ,
2024-02-04 08:00:54 +01:00
Bytecode : : Label { 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 ) ;
2024-02-04 08:00:54 +01:00
auto body = 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 ( ) ) {
2024-02-04 08:00:54 +01:00
if ( body . has_value ( ) )
generator . emit < Bytecode : : Op : : Mov > ( result , body . value ( ) ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { test_block } ) ;
2021-06-09 19:57:18 +02:00
}
2022-02-12 19:54:08 +03:30
2023-06-25 20:52:35 +01:00
generator . switch_to_basic_block ( end_block ) ;
2024-02-04 08:00:54 +01:00
return result ;
2021-06-04 12:07:38 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > DoWhileStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-06-11 23:09:37 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-06-11 23:09:37 +01:00
return generate_labelled_evaluation ( generator , { } ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > DoWhileStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-04 12:20:44 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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 & body_block = generator . make_block ( ) ;
2024-05-06 13:38:08 +02:00
auto & test_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 ( ) ;
2024-05-07 21:36:56 +02:00
auto completion_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( completion_value , generator . add_constant ( js_undefined ( ) ) ) ;
2021-06-09 06:49:58 +04:30
// jump to the body block
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { body_block } ) ;
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( test_block ) ;
2024-02-04 08:00:54 +01:00
auto test = TRY ( m_test - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
test ,
2021-06-09 06:49:58 +04:30
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 ) ;
2024-02-04 08:00:54 +01:00
auto body_result = 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 ( ) ) {
2024-02-04 08:00:54 +01:00
if ( body_result . has_value ( ) )
generator . emit < Bytecode : : Op : : Mov > ( completion_value , body_result . value ( ) ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { test_block } ) ;
2021-06-09 19:57:18 +02:00
}
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 ) ;
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
generator . switch_to_basic_block ( end_block ) ;
2024-02-04 08:00:54 +01:00
return completion_value ;
2021-06-04 12:20:44 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ForStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-06-11 23:09:37 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-06-11 23:09:37 +01:00
return generate_labelled_evaluation ( generator , { } ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ForStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-08 10:54:40 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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 } ;
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 ) ;
2023-07-13 21:30:36 +02:00
auto has_non_local_variables = false ;
MUST ( variable_declaration . for_each_bound_identifier ( [ & ] ( auto const & identifier ) {
if ( ! identifier . is_local ( ) )
has_non_local_variables = true ;
} ) ) ;
if ( variable_declaration . is_lexical_declaration ( ) & & has_non_local_variables ) {
2022-03-14 02:39:24 +00:00
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.
2023-07-13 21:30:36 +02:00
MUST ( variable_declaration . for_each_bound_identifier ( [ & ] ( auto const & identifier ) {
if ( identifier . is_local ( ) )
return ;
auto index = generator . intern_identifier ( identifier . string ( ) ) ;
2022-03-14 02:39:24 +00:00
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
}
}
2024-02-04 08:00:54 +01:00
( void ) 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_update )
update_block_ptr = & generator . make_block ( ) ;
else
update_block_ptr = body_block_ptr ;
2024-05-06 09:34:42 +02:00
if ( m_test )
test_block_ptr = & generator . make_block ( ) ;
else
test_block_ptr = body_block_ptr ;
2024-05-06 10:10:38 +02:00
auto & end_block = generator . make_block ( ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { * test_block_ptr } ) ;
2021-06-09 06:49:58 +04:30
2021-06-08 10:54:40 +01:00
if ( m_test ) {
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( * test_block_ptr ) ;
2023-06-25 20:52:35 +01:00
2024-02-04 08:00:54 +01:00
auto test = TRY ( m_test - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if ( test , Bytecode : : Label { * body_block_ptr } , Bytecode : : Label { end_block } ) ;
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
2024-02-04 08:00:54 +01:00
( void ) TRY ( m_update - > generate_bytecode ( generator ) ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { * test_block_ptr } ) ;
2023-06-15 19:13:00 +02:00
}
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 ) ;
2024-02-04 08:00:54 +01:00
auto body_result = 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 ) {
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { * update_block_ptr } ) ;
2023-06-15 19:13:00 +02:00
} else {
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( 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
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 ( ) ;
2024-02-04 08:00:54 +01:00
return body_result ;
2021-06-08 10:54:40 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ObjectExpression : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-04 20:30:23 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2021-06-04 20:30:23 +02:00
2024-05-07 21:36:56 +02:00
auto object = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : NewObject > ( object ) ;
if ( m_properties . is_empty ( ) )
return object ;
2021-06-11 19:40:48 +03:00
2024-02-04 08:00:54 +01:00
generator . push_home_object ( object ) ;
2023-06-16 10:25:05 +02:00
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 :
2023-07-10 08:44:28 +02:00
property_kind = Bytecode : : Op : : PropertyKind : : DirectKeyValue ;
2022-03-31 00:59:58 +04:30
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
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > value ;
2023-06-25 19:25:38 +02:00
if ( property_kind = = Bytecode : : Op : : PropertyKind : : ProtoSetter ) {
2024-02-04 08:00:54 +01:00
value = TRY ( property - > value ( ) . generate_bytecode ( generator ) ) . value ( ) ;
2023-06-25 19:25:38 +02:00
} else if ( property_kind ! = Bytecode : : Op : : PropertyKind : : Spread ) {
2023-12-16 17:49:34 +03:30
ByteString identifier = string_literal . value ( ) ;
2023-11-05 11:21:32 +01:00
if ( property_kind = = Bytecode : : Op : : PropertyKind : : Getter )
2023-12-16 17:49:34 +03:30
identifier = ByteString : : formatted ( " get {} " , identifier ) ;
2023-11-05 11:21:32 +01:00
else if ( property_kind = = Bytecode : : Op : : PropertyKind : : Setter )
2023-12-16 17:49:34 +03:30
identifier = ByteString : : formatted ( " set {} " , identifier ) ;
2023-11-05 11:21:32 +01:00
auto name = generator . intern_identifier ( identifier ) ;
2024-02-04 08:00:54 +01:00
value = TRY ( generator . emit_named_evaluation_if_anonymous_function ( property - > value ( ) , name ) ) . value ( ) ;
} else {
// Spread the key.
value = TRY ( property - > key ( ) . generate_bytecode ( generator ) ) . value ( ) ;
2023-06-25 19:25:38 +02:00
}
2022-03-31 00:59:58 +04:30
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : PutById > ( object , key_name , * value , property_kind , generator . next_property_lookup_cache ( ) ) ;
2021-06-11 19:40:48 +03:00
} else {
2024-02-04 08:00:54 +01:00
auto property_name = TRY ( property - > key ( ) . generate_bytecode ( generator ) ) . value ( ) ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > value ;
2022-03-31 00:59:58 +04:30
if ( property_kind ! = Bytecode : : Op : : PropertyKind : : Spread )
2024-02-04 08:00:54 +01:00
value = TRY ( property - > value ( ) . generate_bytecode ( generator ) ) . value ( ) ;
else
value = property_name ;
2022-03-31 00:59:58 +04:30
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : PutByValue > ( object , property_name , * value , property_kind ) ;
2021-06-11 19:40:48 +03:00
}
}
2023-06-16 10:25:05 +02:00
generator . pop_home_object ( ) ;
2024-02-04 08:00:54 +01:00
return object ;
2021-06-04 20:30:23 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ArrayExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-08 23:06:52 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-09-09 15:23:02 +02:00
if ( m_elements . is_empty ( ) ) {
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : NewArray > ( dst ) ;
return dst ;
2022-03-14 14:48:42 +00:00
}
2021-06-08 23:06:52 +02:00
2023-11-17 22:07:23 +02:00
if ( all_of ( m_elements , [ ] ( auto element ) { return ! element | | is < PrimitiveLiteral > ( * element ) ; } ) ) {
// If all elements are constant primitives, we can just emit a single instruction to initialize the array,
// instead of emitting instructions to manually evaluate them one-by-one
2024-03-03 12:37:28 +01:00
Vector < Value > values ;
values . resize ( m_elements . size ( ) ) ;
2023-11-17 22:07:23 +02:00
for ( auto i = 0u ; i < m_elements . size ( ) ; + + i ) {
if ( ! m_elements [ i ] )
continue ;
values [ i ] = static_cast < PrimitiveLiteral const & > ( * m_elements [ i ] ) . value ( ) ;
}
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
2024-03-03 12:37:28 +01:00
generator . emit_with_extra_value_slots < Bytecode : : Op : : NewPrimitiveArray > ( values . size ( ) , dst , values ) ;
2024-02-04 08:00:54 +01:00
return dst ;
2023-11-17 22:07:23 +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 ) ; } ) ;
2024-05-08 12:43:08 +02:00
Vector < ScopedOperand > args ;
args . ensure_capacity ( m_elements . size ( ) ) ;
2022-09-09 15:23:02 +02:00
for ( auto it = m_elements . begin ( ) ; it ! = first_spread ; + + it ) {
2024-02-04 08:00:54 +01:00
if ( * it ) {
auto value = TRY ( ( * it ) - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-09 15:22:46 +02:00
// NOTE: We don't need to protect temporary registers or constants from being clobbered.
if ( value . operand ( ) . is_register ( ) | | value . operand ( ) . is_constant ( ) ) {
args . append ( move ( value ) ) ;
} else {
auto reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( Bytecode : : Operand ( reg ) , value ) ;
args . append ( move ( reg ) ) ;
}
2024-05-08 12:43:08 +02:00
} else {
args . append ( generator . add_constant ( Value ( ) ) ) ;
2021-06-08 23:06:52 +02:00
}
}
2022-09-09 15:23:02 +02:00
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
if ( first_spread . index ( ) ! = 0 ) {
2024-05-08 12:43:08 +02:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : NewArray > ( args . size ( ) , dst , args ) ;
2024-02-04 08:00:54 +01:00
} else {
generator . emit < Bytecode : : Op : : NewArray > ( dst ) ;
}
2022-09-09 15:23:02 +02:00
if ( first_spread ! = m_elements . end ( ) ) {
for ( auto it = first_spread ; it ! = m_elements . end ( ) ; + + it ) {
if ( ! * it ) {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ArrayAppend > ( dst , generator . add_constant ( Value ( ) ) , false ) ;
2022-09-09 15:23:02 +02:00
} else {
2024-02-04 08:00:54 +01:00
auto value = TRY ( ( * it ) - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : ArrayAppend > ( dst , value , * it & & is < SpreadExpression > ( * * it ) ) ;
2022-09-09 15:23:02 +02:00
}
}
2022-03-14 14:48:42 +00:00
}
2022-09-09 15:23:02 +02:00
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-08 23:06:52 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > MemberExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-04 21:03:53 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto reference = TRY ( generator . emit_load_from_reference ( * this , preferred_dst ) ) ;
return reference . loaded_value ;
2021-06-04 21:03:53 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > FunctionDeclaration : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-05 15:15:30 +02:00
{
2022-02-12 19:48:45 +03:30
if ( m_is_hoisted ) {
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-02-12 19:48:45 +03:30
auto index = generator . intern_identifier ( name ( ) ) ;
2024-05-07 21:36:56 +02:00
auto value = generator . allocate_register ( ) ;
2024-05-11 18:28:03 +02:00
generator . emit < Bytecode : : Op : : GetVariable > ( value , index ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( index , value , Bytecode : : Op : : SetVariable : : InitializationMode : : Set , Bytecode : : Op : : EnvironmentMode : : Var ) ;
2022-02-12 19:48:45 +03:30
}
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2021-06-05 15:15:30 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > FunctionExpression : : generate_bytecode_with_lhs_name ( Bytecode : : Generator & generator , Optional < Bytecode : : IdentifierTableIndex > lhs_name , Optional < ScopedOperand > preferred_dst ) const
2021-06-11 10:46:46 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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 ) ;
}
2024-02-04 08:00:54 +01:00
auto new_function = choose_dst ( generator , preferred_dst ) ;
generator . emit_new_function ( new_function , * this , lhs_name ) ;
2022-06-11 23:24:55 +01:00
if ( has_name ) {
2024-05-11 18:28:03 +02:00
generator . emit < Bytecode : : Op : : SetVariable > ( * name_identifier , new_function , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , Bytecode : : Op : : EnvironmentMode : : Lexical ) ;
2022-06-11 23:24:55 +01:00
generator . end_variable_scope ( ) ;
}
2024-02-04 08:00:54 +01:00
return new_function ;
2021-06-11 10:46:46 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > FunctionExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2023-06-23 14:27:42 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
return generate_bytecode_with_lhs_name ( generator , { } , preferred_dst ) ;
2023-06-23 14:27:42 +02:00
}
2024-05-07 21:36:56 +02:00
static Bytecode : : CodeGenerationErrorOr < void > generate_object_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode initialization_mode , ScopedOperand const & object , bool create_variables )
2021-06-13 12:24:55 -07:00
{
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ThrowIfNullish > ( object ) ;
2023-06-25 08:50:07 +02:00
2024-05-07 21:36:56 +02:00
Vector < ScopedOperand > excluded_property_names ;
2021-06-13 15:30:32 -07:00
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 ) {
VERIFY ( ! initializer ) ;
2023-07-02 11:24:55 +02:00
if ( name . has < NonnullRefPtr < Identifier const > > ( ) ) {
2023-07-05 02:17:10 +02:00
auto identifier = name . get < NonnullRefPtr < Identifier const > > ( ) ;
auto interned_identifier = generator . intern_identifier ( identifier - > string ( ) ) ;
2021-06-13 15:30:32 -07:00
2024-05-07 21:36:56 +02:00
auto copy = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : CopyObjectExcludingProperties > (
excluded_property_names . size ( ) , copy , object , excluded_property_names ) ;
2023-07-05 02:17:10 +02:00
if ( create_variables ) {
VERIFY ( ! identifier - > is_local ( ) ) ;
2023-07-02 11:24:55 +02:00
generator . emit < Bytecode : : Op : : CreateVariable > ( interned_identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
2023-07-05 02:17:10 +02:00
}
2024-02-04 08:00:54 +01:00
generator . emit_set_variable ( * identifier , copy , initialization_mode ) ;
2021-06-13 15:30:32 -07:00
2024-02-04 08:00:54 +01:00
return { } ;
2023-07-02 11:24:55 +02:00
}
if ( alias . has < NonnullRefPtr < MemberExpression const > > ( ) ) {
2024-05-07 21:36:56 +02:00
auto copy = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : CopyObjectExcludingProperties > (
excluded_property_names . size ( ) , copy , object , excluded_property_names ) ;
( void ) TRY ( generator . emit_store_to_reference ( alias . get < NonnullRefPtr < MemberExpression const > > ( ) , object ) ) ;
return { } ;
2023-07-02 11:24:55 +02:00
}
VERIFY_NOT_REACHED ( ) ;
2021-06-13 15:30:32 -07:00
}
2021-06-13 12:24:55 -07:00
2024-05-07 21:36:56 +02:00
auto value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
2023-02-19 22:07:52 +01:00
if ( name . has < NonnullRefPtr < Identifier const > > ( ) ) {
2024-03-03 11:34:36 +01:00
auto const & identifier = name . get < NonnullRefPtr < Identifier const > > ( ) - > string ( ) ;
2021-06-13 15:30:32 -07:00
if ( has_rest ) {
2024-03-03 11:34:36 +01:00
excluded_property_names . append ( generator . add_constant ( PrimitiveString : : create ( generator . vm ( ) , identifier ) , Bytecode : : Generator : : DeduplicateConstant : : No ) ) ;
2021-06-13 15:30:32 -07:00
}
2024-02-04 08:00:54 +01:00
generator . emit_get_by_id ( value , object , 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 > > ( ) ;
2024-02-04 08:00:54 +01:00
auto property_name = TRY ( expression - > generate_bytecode ( generator ) ) . value ( ) ;
2021-06-13 15:30:32 -07:00
if ( has_rest ) {
2024-05-07 21:36:56 +02:00
auto excluded_name = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
excluded_property_names . append ( excluded_name ) ;
generator . emit < Bytecode : : Op : : Mov > ( excluded_name , property_name ) ;
2021-06-13 15:30:32 -07:00
}
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetByValue > ( value , object , property_name ) ;
2021-06-13 13:40:48 -07:00
}
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
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : JumpUndefined > (
2024-02-04 08:00:54 +01:00
value ,
2021-06-13 13:40:48 -07:00
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 ) ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > default_value ;
2023-06-27 14:41:09 +02:00
if ( auto const * alias_identifier = alias . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
2024-02-04 08:00:54 +01:00
default_value = TRY ( generator . emit_named_evaluation_if_anonymous_function ( * initializer , generator . intern_identifier ( ( * alias_identifier ) - > string ( ) ) ) ) . value ( ) ;
2023-06-27 14:41:09 +02:00
} else if ( auto const * lhs = name . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
2024-02-04 08:00:54 +01:00
default_value = TRY ( generator . emit_named_evaluation_if_anonymous_function ( * initializer , generator . intern_identifier ( ( * lhs ) - > string ( ) ) ) ) . value ( ) ;
2023-06-23 14:27:42 +02:00
} else {
2024-02-04 08:00:54 +01:00
default_value = TRY ( initializer - > generate_bytecode ( generator ) ) . value ( ) ;
2023-06-23 14:27:42 +02:00
}
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( value , * default_value ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( 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 > > ( ) ;
2024-05-07 21:36:56 +02:00
auto nested_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( nested_value , value ) ;
2024-05-09 05:00:07 +00:00
TRY ( binding_pattern . generate_bytecode ( generator , initialization_mode , nested_value , 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-07-05 02:17:10 +02:00
auto const & identifier = * name . get < NonnullRefPtr < Identifier const > > ( ) ;
auto identifier_ref = generator . intern_identifier ( identifier . string ( ) ) ;
2023-06-24 20:29:30 +02:00
if ( create_variables )
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier_ref , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
2024-02-04 08:00:54 +01:00
generator . emit_set_variable ( identifier , value , initialization_mode ) ;
2023-06-25 16:24:05 +02:00
} else if ( alias . has < NonnullRefPtr < MemberExpression const > > ( ) ) {
2024-02-04 08:00:54 +01:00
TRY ( generator . emit_store_to_reference ( alias . get < NonnullRefPtr < MemberExpression const > > ( ) , value ) ) ;
2021-06-13 12:24:55 -07:00
} else {
2023-07-05 02:17:10 +02:00
auto const & identifier = * alias . get < NonnullRefPtr < Identifier const > > ( ) ;
auto identifier_ref = generator . intern_identifier ( identifier . string ( ) ) ;
2023-06-24 20:29:30 +02:00
if ( create_variables )
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier_ref , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
2024-02-04 08:00:54 +01:00
generator . emit_set_variable ( identifier , value , initialization_mode ) ;
2021-06-13 13:40:48 -07:00
}
}
2024-02-04 08:00:54 +01:00
return { } ;
2021-06-13 13:40:48 -07:00
}
2024-05-07 21:36:56 +02:00
static Bytecode : : CodeGenerationErrorOr < void > generate_array_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode initialization_mode , ScopedOperand const & input_array , bool create_variables , [[maybe_unused]] Optional < ScopedOperand > preferred_dst = { } )
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 .
2024-02-04 08:00:54 +01:00
* If it is ' true ' , we load undefined . Otherwise , we grab the next value from the iterator .
2021-06-13 13:40:48 -07:00
*
* 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 .
*/
2024-05-07 21:36:56 +02:00
auto is_iterator_exhausted = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( is_iterator_exhausted , generator . add_constant ( Value ( false ) ) ) ;
2021-06-13 13:40:48 -07:00
2024-05-07 21:36:56 +02:00
auto iterator = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetIterator > ( iterator , input_array ) ;
2021-06-13 13:40:48 -07:00
bool first = true ;
2024-05-07 21:36:56 +02:00
auto assign_value_to_alias = [ & ] ( auto & alias , ScopedOperand value ) {
2022-02-12 19:54:08 +03:30
return alias . visit (
2024-02-04 08:00:54 +01:00
[ & ] ( Empty ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-06-13 14:06:26 -07:00
// This element is an elision
2024-02-04 08:00:54 +01:00
return { } ;
2021-06-13 14:06:26 -07:00
} ,
2024-02-04 08:00:54 +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 ) ;
2024-02-04 08:00:54 +01:00
generator . emit_set_variable ( * identifier , value , initialization_mode ) ;
return { } ;
2021-06-13 14:06:26 -07:00
} ,
2024-02-04 08:00:54 +01:00
[ & ] ( NonnullRefPtr < BindingPattern const > const & pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
2024-05-09 05:00:07 +00:00
return pattern - > generate_bytecode ( generator , initialization_mode , value , create_variables ) ;
2021-09-18 01:11:32 +02:00
} ,
2024-02-04 08:00:54 +01:00
[ & ] ( NonnullRefPtr < MemberExpression const > const & expr ) - > Bytecode : : CodeGenerationErrorOr < void > {
( void ) generator . emit_store_to_reference ( * expr , value ) ;
return { } ;
2021-06-13 14:06:26 -07:00
} ) ;
} ;
2024-05-07 21:36:56 +02:00
auto temp_iterator_result = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01: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 ) ;
2024-05-07 21:36:56 +02:00
auto value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
2021-06-13 14:06:26 -07:00
if ( first ) {
// The iterator has not been called, and is thus known to be not exhausted
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : IteratorToArray > ( value , iterator ) ;
2021-06-13 14:06:26 -07:00
} else {
auto & if_exhausted_block = generator . make_block ( ) ;
auto & if_not_exhausted_block = generator . make_block ( ) ;
auto & continuation_block = generator . make_block ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
is_iterator_exhausted ,
2021-06-13 14:06:26 -07:00
Bytecode : : Label { if_exhausted_block } ,
Bytecode : : Label { if_not_exhausted_block } ) ;
2024-05-07 21:36:56 +02:00
value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
2021-06-13 14:06:26 -07:00
generator . switch_to_basic_block ( if_exhausted_block ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : NewArray > ( value ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { continuation_block } ) ;
2021-06-13 14:06:26 -07:00
generator . switch_to_basic_block ( if_not_exhausted_block ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : IteratorToArray > ( value , iterator ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { continuation_block } ) ;
2021-06-13 14:06:26 -07:00
generator . switch_to_basic_block ( continuation_block ) ;
}
2024-02-04 08:00:54 +01:00
return assign_value_to_alias ( alias , value ) ;
2021-06-13 14:06:26 -07:00
}
2021-06-13 13:40:48 -07:00
auto & iterator_is_exhausted_block = generator . make_block ( ) ;
if ( ! first ) {
auto & iterator_is_not_exhausted_block = generator . make_block ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
is_iterator_exhausted ,
2021-06-13 13:40:48 -07:00
Bytecode : : Label { iterator_is_exhausted_block } ,
Bytecode : : Label { iterator_is_not_exhausted_block } ) ;
generator . switch_to_basic_block ( iterator_is_not_exhausted_block ) ;
2021-06-13 12:24:55 -07:00
}
2021-06-13 13:40:48 -07:00
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : IteratorNext > ( temp_iterator_result , iterator ) ;
generator . emit_iterator_complete ( is_iterator_exhausted , temp_iterator_result ) ;
2021-06-13 13:40:48 -07:00
// 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 ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
is_iterator_exhausted ,
2021-06-13 13:40:48 -07:00
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
2024-05-07 21:36:56 +02:00
auto value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_iterator_value ( value , temp_iterator_result ) ;
2021-06-13 13:40:48 -07:00
auto & create_binding_block = generator . make_block ( ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { create_binding_block } ) ;
2021-06-13 13:40:48 -07:00
// The iterator is exhausted, so we just load undefined and continue binding
generator . switch_to_basic_block ( iterator_is_exhausted_block ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( value , generator . add_constant ( js_undefined ( ) ) ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { create_binding_block } ) ;
2021-06-13 13:40:48 -07:00
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 ( ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : JumpUndefined > (
2024-02-04 08:00:54 +01:00
value ,
2022-07-17 19:25:23 +01:00
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
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > default_value ;
2023-06-25 11:11:36 +02:00
if ( auto const * alias_identifier = alias . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
2024-02-04 08:00:54 +01:00
default_value = TRY ( generator . emit_named_evaluation_if_anonymous_function ( * initializer , generator . intern_identifier ( ( * alias_identifier ) - > string ( ) ) ) ) . value ( ) ;
2023-06-25 11:11:36 +02:00
} else if ( auto const * name_identifier = name . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
2024-02-04 08:00:54 +01:00
default_value = TRY ( generator . emit_named_evaluation_if_anonymous_function ( * initializer , generator . intern_identifier ( ( * name_identifier ) - > string ( ) ) ) ) . value ( ) ;
2023-06-23 14:27:42 +02:00
} else {
2024-02-04 08:00:54 +01:00
default_value = TRY ( initializer - > generate_bytecode ( generator ) ) . value ( ) ;
2023-06-23 14:27:42 +02:00
}
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( value , * default_value ) ;
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 ) ;
}
2024-02-04 08:00:54 +01:00
TRY ( assign_value_to_alias ( alias , value ) ) ;
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 ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
is_iterator_exhausted ,
2023-06-26 17:21:12 +02:00
Bytecode : : Label { done_block } ,
Bytecode : : Label { not_done_block } ) ;
generator . switch_to_basic_block ( not_done_block ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : IteratorClose > ( iterator , Completion : : Type : : Normal , Optional < Value > { } ) ;
2023-06-26 17:21:12 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { done_block } ) ;
generator . switch_to_basic_block ( done_block ) ;
2024-02-04 08:00:54 +01:00
return { } ;
2021-06-13 13:40:48 -07:00
}
2024-05-09 05:00:07 +00:00
Bytecode : : CodeGenerationErrorOr < void > BindingPattern : : generate_bytecode ( Bytecode : : Generator & generator , Bytecode : : Op : : SetVariable : : InitializationMode initialization_mode , ScopedOperand const & input_value , bool create_variables ) const
2021-06-13 13:40:48 -07:00
{
2024-05-09 05:00:07 +00:00
if ( kind = = Kind : : Object )
return generate_object_binding_pattern_bytecode ( generator , * this , initialization_mode , input_value , create_variables ) ;
2022-02-12 19:54:08 +03:30
2024-05-09 05:00:07 +00:00
return generate_array_binding_pattern_bytecode ( generator , * this , initialization_mode , input_value , create_variables ) ;
2022-02-12 19:54:08 +03:30
}
2021-06-13 12:24:55 -07:00
2024-05-07 21:36:56 +02:00
static Bytecode : : CodeGenerationErrorOr < void > assign_value_to_variable_declarator ( Bytecode : : Generator & generator , VariableDeclarator const & declarator , VariableDeclaration const & declaration , ScopedOperand value )
2022-03-18 20:18:19 +03:30
{
auto initialization_mode = declaration . is_lexical_declaration ( ) ? Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize : Bytecode : : Op : : SetVariable : : InitializationMode : : Set ;
return declarator . target ( ) . visit (
2024-02-04 08:00:54 +01:00
[ & ] ( NonnullRefPtr < Identifier const > const & id ) - > Bytecode : : CodeGenerationErrorOr < void > {
generator . emit_set_variable ( * id , value , initialization_mode ) ;
return { } ;
2022-03-18 20:18:19 +03:30
} ,
2024-02-04 08:00:54 +01:00
[ & ] ( NonnullRefPtr < BindingPattern const > const & pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
2024-05-09 05:00:07 +00:00
return pattern - > generate_bytecode ( generator , initialization_mode , value , false ) ;
2022-03-18 20:18:19 +03:30
} ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > VariableDeclaration : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-10 00:29:17 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2023-07-02 10:48:17 +02:00
2021-06-10 22:12:21 +02:00
for ( auto & declarator : m_declarations ) {
2024-03-01 12:54:50 +01:00
// NOTE: `var` declarations can have duplicates, but duplicate `let` or `const` bindings are a syntax error.
// Because of this, we can sink `let` and `const` directly into the preferred_dst if available.
// This is not safe for `var` since the preferred_dst may be used in the initializer.
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > init_dst ;
2024-03-01 12:54:50 +01:00
if ( declaration_kind ( ) ! = DeclarationKind : : Var ) {
if ( auto const * identifier = declarator - > target ( ) . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
if ( ( * identifier ) - > is_local ( ) ) {
2024-05-07 21:36:56 +02:00
init_dst = generator . local ( ( * identifier ) - > local_variable_index ( ) ) ;
2024-03-01 12:54:50 +01:00
}
2023-06-23 14:27:42 +02:00
}
2024-02-04 08:00:54 +01:00
}
if ( declarator - > init ( ) ) {
2024-05-07 21:36:56 +02:00
auto value = TRY ( [ & ] ( ) - > Bytecode : : CodeGenerationErrorOr < ScopedOperand > {
2024-02-04 08:00:54 +01:00
if ( auto const * lhs = declarator - > target ( ) . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
return TRY ( generator . emit_named_evaluation_if_anonymous_function ( * declarator - > init ( ) , generator . intern_identifier ( ( * lhs ) - > string ( ) ) , init_dst ) ) . value ( ) ;
} else {
return TRY ( declarator - > init ( ) - > generate_bytecode ( generator , init_dst ) ) . value ( ) ;
}
} ( ) ) ;
( void ) TRY ( assign_value_to_variable_declarator ( generator , declarator , * this , value ) ) ;
2023-06-17 15:16:30 +02:00
} else if ( m_declaration_kind ! = DeclarationKind : : Var ) {
2024-02-04 08:00:54 +01:00
( void ) TRY ( assign_value_to_variable_declarator ( generator , declarator , * this , generator . add_constant ( js_undefined ( ) ) ) ) ;
2023-06-17 15:16:30 +02:00
}
2021-06-10 22:12:21 +02:00
}
2022-02-12 19:54:08 +03:30
2024-02-04 08:00:54 +01:00
for ( auto & declarator : m_declarations ) {
if ( auto const * identifier = declarator - > target ( ) . get_pointer < NonnullRefPtr < Identifier const > > ( ) ) {
if ( ( * identifier ) - > is_local ( ) ) {
generator . set_local_initialized ( ( * identifier ) - > local_variable_index ( ) ) ;
}
}
}
// NOTE: VariableDeclaration doesn't return a completion value.
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2021-06-10 00:29:17 +02:00
}
2024-02-04 08:00:54 +01:00
struct BaseAndValue {
2024-05-07 21:36:56 +02:00
ScopedOperand base ;
ScopedOperand value ;
2024-02-04 08:00:54 +01:00
} ;
static Bytecode : : CodeGenerationErrorOr < BaseAndValue > get_base_and_value_from_member_expression ( Bytecode : : Generator & generator , MemberExpression const & member_expression )
2023-06-17 14:50:23 +01:00
{
// 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().
2024-05-07 12:16:37 +02:00
auto this_value = generator . get_this ( ) ;
2023-06-17 14:50:23 +01:00
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > computed_property ;
2023-06-17 14:50:23 +01:00
if ( member_expression . is_computed ( ) ) {
// SuperProperty : super [ Expression ]
// 3. Let propertyNameReference be ? Evaluation of Expression.
// 4. Let propertyNameValue be ? GetValue(propertyNameReference).
2024-02-04 08:00:54 +01:00
computed_property = TRY ( member_expression . property ( ) . generate_bytecode ( generator ) ) ;
2023-06-17 14:50:23 +01:00
}
// 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().
2024-05-07 21:36:56 +02:00
auto super_base = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ResolveSuperBase > ( super_base ) ;
2024-05-07 21:36:56 +02:00
auto value = generator . allocate_register ( ) ;
2023-06-17 14:50:23 +01:00
// 4. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }.
2024-02-04 08:00:54 +01:00
if ( computed_property . has_value ( ) ) {
2023-06-17 14:50:23 +01:00
// 5. Let propertyKey be ? ToPropertyKey(propertyNameValue).
// FIXME: This does ToPropertyKey out of order, which is observable by Symbol.toPrimitive!
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetByValueWithThis > ( value , super_base , * computed_property , this_value ) ;
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 ( ) ) ;
2024-02-04 08:00:54 +01:00
generator . emit_get_by_id_with_this ( value , super_base , identifier_table_ref , this_value ) ;
2023-06-17 14:50:23 +01:00
}
2024-02-04 08:00:54 +01:00
return BaseAndValue { this_value , value } ;
}
auto base = TRY ( member_expression . object ( ) . generate_bytecode ( generator ) ) . value ( ) ;
2024-05-07 21:36:56 +02:00
auto value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
if ( member_expression . is_computed ( ) ) {
auto property = TRY ( member_expression . property ( ) . generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : GetByValue > ( value , base , property ) ;
} else if ( is < PrivateIdentifier > ( member_expression . property ( ) ) ) {
generator . emit < Bytecode : : Op : : GetPrivateById > (
value ,
base ,
generator . intern_identifier ( verify_cast < PrivateIdentifier > ( member_expression . property ( ) ) . string ( ) ) ) ;
2023-06-17 14:50:23 +01:00
} else {
2024-03-29 11:26:10 -04:00
auto base_identifier = generator . intern_identifier_for_expression ( member_expression . object ( ) ) ;
generator . emit_get_by_id ( value , base , generator . intern_identifier ( verify_cast < Identifier > ( member_expression . property ( ) ) . string ( ) ) , move ( base_identifier ) ) ;
2023-06-17 14:50:23 +01:00
}
2024-02-04 08:00:54 +01:00
return BaseAndValue { base , value } ;
2023-06-17 14:50:23 +01:00
}
2024-05-07 21:36:56 +02:00
static Bytecode : : CodeGenerationErrorOr < void > generate_optional_chain ( Bytecode : : Generator & generator , OptionalChain const & optional_chain , ScopedOperand current_value , ScopedOperand current_base , [[maybe_unused]] Optional < ScopedOperand > preferred_dst = { } ) ;
2023-06-17 14:50:23 +01:00
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > CallExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-05 15:15:30 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2021-06-05 15:15:30 +02:00
2023-11-17 11:48:30 +01:00
Optional < Bytecode : : Builtin > builtin ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > original_callee ;
2024-02-04 08:00:54 +01:00
auto this_value = generator . add_constant ( js_undefined ( ) ) ;
2021-06-11 01:36:10 +04:30
if ( is < NewExpression > ( this ) ) {
2024-02-04 08:00:54 +01:00
original_callee = TRY ( m_callee - > generate_bytecode ( generator ) ) . value ( ) ;
2021-06-11 01:36:10 +04:30
} else if ( is < MemberExpression > ( * m_callee ) ) {
2022-04-01 20:58:27 +03:00
auto & member_expression = static_cast < MemberExpression const & > ( * m_callee ) ;
2024-02-04 08:00:54 +01:00
auto base_and_value = TRY ( get_base_and_value_from_member_expression ( generator , member_expression ) ) ;
original_callee = base_and_value . value ;
this_value = base_and_value . base ;
2023-11-17 11:48:30 +01:00
builtin = Bytecode : : get_builtin ( member_expression ) ;
2023-06-17 14:50:23 +01:00
} else if ( is < OptionalChain > ( * m_callee ) ) {
auto & optional_chain = static_cast < OptionalChain const & > ( * m_callee ) ;
2024-05-07 21:36:56 +02:00
original_callee = generator . allocate_register ( ) ;
this_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
TRY ( generate_optional_chain ( generator , optional_chain , * original_callee , this_value ) ) ;
2023-08-01 14:33:58 +02:00
} else if ( is < Identifier > ( * m_callee ) ) {
2024-02-04 08:00:54 +01:00
// If the original_callee is an identifier, we may need to extract a `this` value.
2023-08-01 14:33:58 +02:00
// This is important when we're inside a `with` statement and calling a method on
// the environment's binding object.
// NOTE: If the identifier refers to a known "local" or "global", we know it can't be
// a `with` binding, so we can skip this.
auto & identifier = static_cast < Identifier const & > ( * m_callee ) ;
2024-02-04 08:00:54 +01:00
if ( identifier . is_local ( ) ) {
2024-05-07 21:36:56 +02:00
auto local = generator . local ( identifier . local_variable_index ( ) ) ;
if ( ! generator . is_local_initialized ( local . operand ( ) . index ( ) ) ) {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ThrowIfTDZ > ( local ) ;
}
original_callee = local ;
} else if ( identifier . is_global ( ) ) {
original_callee = m_callee - > generate_bytecode ( generator ) . value ( ) ;
2023-08-01 14:33:58 +02:00
} else {
2024-05-07 21:36:56 +02:00
original_callee = generator . allocate_register ( ) ;
this_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetCalleeAndThisFromEnvironment > (
* original_callee ,
this_value ,
2024-05-11 18:28:03 +02:00
generator . intern_identifier ( identifier . string ( ) ) ) ;
2023-08-01 14:33:58 +02:00
}
2021-06-11 01:36:10 +04:30
} else {
// FIXME: this = global object in sloppy mode.
2024-02-04 08:00:54 +01:00
original_callee = TRY ( m_callee - > generate_bytecode ( generator ) ) . value ( ) ;
2021-06-11 01:36:10 +04:30
}
2024-05-09 19:52:38 +02:00
// NOTE: If the callee isn't already a temporary, we copy it to a new register
// to avoid overwriting it while evaluating arguments.
auto callee = [ & ] ( ) - > ScopedOperand {
if ( ! original_callee - > operand ( ) . is_register ( ) ) {
auto callee = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( callee , * original_callee ) ;
return callee ;
}
return * original_callee ;
} ( ) ;
2024-02-04 08:00:54 +01:00
2023-07-02 15:59:54 +02:00
Bytecode : : Op : : CallType call_type ;
2021-06-10 23:01:49 +02:00
if ( is < NewExpression > ( * this ) ) {
2023-07-02 15:59:54 +02:00
call_type = Bytecode : : Op : : 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 ) {
2023-07-02 15:59:54 +02:00
call_type = Bytecode : : Op : : CallType : : DirectEval ;
2021-06-10 23:01:49 +02:00
} else {
2023-07-02 15:59:54 +02:00
call_type = Bytecode : : Op : : CallType : : Call ;
2021-06-10 23:01:49 +02:00
}
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 ( ) ) ;
2023-07-02 16:33:00 +02:00
bool has_spread = any_of ( arguments ( ) , [ ] ( auto & argument ) { return argument . is_spread ; } ) ;
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
2023-07-02 16:33:00 +02:00
if ( has_spread ) {
2024-02-04 08:00:54 +01:00
auto arguments = TRY ( arguments_to_array_for_call ( generator , this - > arguments ( ) ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : CallWithArgumentArray > ( call_type , dst , callee , this_value , arguments , expression_string_index ) ;
2023-07-02 16:33:00 +02:00
} else {
2024-05-07 21:36:56 +02:00
Vector < ScopedOperand > argument_operands ;
2024-05-08 12:43:08 +02:00
argument_operands . ensure_capacity ( arguments ( ) . size ( ) ) ;
2023-07-02 16:33:00 +02:00
for ( auto const & argument : arguments ( ) ) {
2024-04-27 16:04:09 +02:00
auto argument_value = TRY ( argument . value - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-09 15:22:46 +02:00
// NOTE: We don't need to protect temporary registers or constants from being clobbered.
if ( argument_value . operand ( ) . is_register ( ) | | argument_value . operand ( ) . is_constant ( ) ) {
argument_operands . append ( argument_value ) ;
} else {
auto temporary = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( temporary , argument_value ) ;
argument_operands . append ( temporary ) ;
}
2023-07-02 16:33:00 +02:00
}
2024-02-20 15:59:45 +01:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : Call > (
argument_operands . size ( ) ,
call_type ,
dst ,
callee ,
this_value ,
argument_operands ,
expression_string_index ,
builtin ) ;
2023-07-02 16:33:00 +02:00
}
2022-10-01 01:36:06 +02:00
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-05 15:15:30 +02:00
}
2024-05-07 21:36:56 +02:00
static ScopedOperand generate_await (
2024-02-04 08:00:54 +01:00
Bytecode : : Generator & generator ,
2024-05-07 21:36:56 +02:00
ScopedOperand argument ,
ScopedOperand received_completion ,
ScopedOperand received_completion_type ,
ScopedOperand received_completion_value ,
2024-02-04 08:00:54 +01:00
Bytecode : : IdentifierTableIndex type_identifier ,
Bytecode : : IdentifierTableIndex value_identifier ) ;
2023-08-09 22:12:07 +01:00
// https://tc39.es/ecma262/#sec-return-statement-runtime-semantics-evaluation
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ReturnStatement : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > ) const
2021-06-05 15:53:36 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > return_value ;
2024-02-04 08:00:54 +01:00
2023-08-09 22:12:07 +01:00
if ( m_argument ) {
// ReturnStatement : return Expression ;
// 1. Let exprRef be ? Evaluation of Expression.
// 2. Let exprValue be ? GetValue(exprRef).
2024-02-04 08:00:54 +01:00
return_value = TRY ( m_argument - > generate_bytecode ( generator ) ) . value ( ) ;
2023-08-09 22:12:07 +01:00
// 3. If GetGeneratorKind() is async, set exprValue to ? Await(exprValue).
// Spec Issue?: The spec doesn't seem to do implicit await on explicit return for async functions, but does for
// async generators. However, the major engines do so, and this is observable via constructor lookups
// on Promise objects and custom thenables.
// See: https://tc39.es/ecma262/#sec-asyncblockstart
// c. Assert: If we return here, the async function either threw an exception or performed an implicit or explicit return; all awaiting is done.
if ( generator . is_in_async_function ( ) ) {
2024-05-07 21:36:56 +02:00
auto received_completion = generator . allocate_register ( ) ;
auto received_completion_type = generator . allocate_register ( ) ;
auto received_completion_value = generator . allocate_register ( ) ;
2023-08-09 22:12:07 +01:00
auto type_identifier = generator . intern_identifier ( " type " ) ;
auto value_identifier = generator . intern_identifier ( " value " ) ;
2024-02-04 08:00:54 +01:00
return_value = generate_await ( generator , * return_value , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
2023-08-09 22:12:07 +01:00
}
// 4. Return Completion Record { [[Type]]: return, [[Value]]: exprValue, [[Target]]: empty }.
} else {
// ReturnStatement : return ;
// 1. Return Completion Record { [[Type]]: return, [[Value]]: undefined, [[Target]]: empty }.
2024-02-04 08:00:54 +01:00
return_value = generator . add_constant ( js_undefined ( ) ) ;
2023-08-09 22:12:07 +01:00
}
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 > ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Yield > ( nullptr , * return_value ) ;
2022-03-13 11:51:02 +03:30
} else {
generator . perform_needed_unwinds < Bytecode : : Op : : Return > ( ) ;
2024-05-07 21:36:56 +02:00
generator . emit < Bytecode : : Op : : Return > ( return_value . has_value ( ) ? return_value - > operand ( ) : Optional < Operand > { } ) ;
2022-03-13 11:51:02 +03:30
}
2022-02-12 19:54:08 +03:30
2024-02-04 08:00:54 +01:00
return return_value ;
2021-06-11 01:38:30 +04:30
}
2024-02-04 08:00:54 +01:00
static void get_received_completion_type_and_value (
Bytecode : : Generator & generator ,
2024-05-07 21:36:56 +02:00
ScopedOperand received_completion ,
ScopedOperand received_completion_type ,
ScopedOperand received_completion_value ,
2024-02-04 08:00:54 +01:00
Bytecode : : IdentifierTableIndex type_identifier ,
Bytecode : : IdentifierTableIndex value_identifier )
2023-07-14 21:57:49 +01:00
{
2024-02-04 08:00:54 +01:00
generator . emit_get_by_id ( received_completion_type , received_completion , type_identifier ) ;
generator . emit_get_by_id ( received_completion_value , received_completion , value_identifier ) ;
2023-07-14 21:57:49 +01:00
}
enum class AwaitBeforeYield {
No ,
Yes ,
} ;
2024-02-04 08:00:54 +01:00
static void generate_yield ( Bytecode : : Generator & generator ,
Bytecode : : Label continuation_label ,
2024-05-07 21:36:56 +02:00
ScopedOperand argument ,
ScopedOperand received_completion ,
ScopedOperand received_completion_type ,
ScopedOperand received_completion_value ,
2024-02-04 08:00:54 +01:00
Bytecode : : IdentifierTableIndex type_identifier ,
Bytecode : : IdentifierTableIndex value_identifier ,
AwaitBeforeYield await_before_yield )
2023-07-14 21:57:49 +01:00
{
if ( ! generator . is_in_async_generator_function ( ) ) {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Yield > ( Bytecode : : Label { continuation_label } , argument ) ;
2023-07-14 21:57:49 +01:00
return ;
}
if ( await_before_yield = = AwaitBeforeYield : : Yes )
2024-02-04 08:00:54 +01:00
argument = generate_await ( generator , argument , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
2023-07-14 21:57:49 +01:00
auto & unwrap_yield_resumption_block = generator . make_block ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Yield > ( Bytecode : : Label { unwrap_yield_resumption_block } , argument ) ;
2023-07-14 21:57:49 +01:00
generator . switch_to_basic_block ( unwrap_yield_resumption_block ) ;
2024-02-04 08:00:54 +01:00
2024-05-07 21:36:56 +02:00
generator . emit < Bytecode : : Op : : Mov > ( received_completion , generator . accumulator ( ) ) ;
2024-02-04 08:00:54 +01:00
get_received_completion_type_and_value ( generator , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
2023-07-14 21:57:49 +01:00
// 27.6.3.7 AsyncGeneratorUnwrapYieldResumption ( resumptionValue ), https://tc39.es/ecma262/#sec-asyncgeneratorunwrapyieldresumption
// 1. If resumptionValue.[[Type]] is not return, return ? resumptionValue.
auto & resumption_value_type_is_return_block = generator . make_block ( ) ;
2024-05-07 21:36:56 +02:00
auto resumption_value_type_is_not_return_result = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyInequals > (
resumption_value_type_is_not_return_result ,
received_completion_type ,
generator . add_constant ( Value ( to_underlying ( Completion : : Type : : Return ) ) ) ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
resumption_value_type_is_not_return_result ,
Bytecode : : Label { continuation_label } ,
2023-07-14 21:57:49 +01:00
Bytecode : : Label { resumption_value_type_is_return_block } ) ;
generator . switch_to_basic_block ( resumption_value_type_is_return_block ) ;
// 2. Let awaited be Completion(Await(resumptionValue.[[Value]])).
2024-02-04 08:00:54 +01:00
generate_await ( generator , received_completion_value , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
2023-07-14 21:57:49 +01:00
// 3. If awaited.[[Type]] is throw, return ? awaited.
auto & awaited_type_is_normal_block = generator . make_block ( ) ;
2024-05-07 21:36:56 +02:00
auto awaited_type_is_throw_result = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyEquals > (
awaited_type_is_throw_result ,
received_completion_type ,
generator . add_constant ( Value ( to_underlying ( Completion : : Type : : Throw ) ) ) ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
awaited_type_is_throw_result ,
Bytecode : : Label { continuation_label } ,
2023-07-14 21:57:49 +01:00
Bytecode : : Label { awaited_type_is_normal_block } ) ;
// 4. Assert: awaited.[[Type]] is normal.
generator . switch_to_basic_block ( awaited_type_is_normal_block ) ;
// 5. Return Completion Record { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }.
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : PutById > (
received_completion ,
type_identifier ,
generator . add_constant ( Value ( to_underlying ( Completion : : Type : : Return ) ) ) ,
Bytecode : : Op : : PropertyKind : : KeyValue ,
generator . next_property_lookup_cache ( ) ) ;
2023-07-14 21:57:49 +01:00
generator . emit < Bytecode : : Op : : Jump > ( continuation_label ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > YieldExpression : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-11 01:38:30 +04:30
{
2024-05-06 22:38:43 +02:00
// Note: We need to catch any scheduled exceptions and reschedule them on re-entry
// as the act of yielding would otherwise clear them out
// This only applies when we are in a finalizer
bool is_in_finalizer = generator . is_in_finalizer ( ) ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > saved_exception ;
2024-05-06 22:38:43 +02:00
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2021-06-11 01:38:30 +04:30
VERIFY ( generator . is_in_generator_function ( ) ) ;
2024-05-07 21:36:56 +02:00
auto received_completion = generator . allocate_register ( ) ;
auto received_completion_type = generator . allocate_register ( ) ;
auto received_completion_value = generator . allocate_register ( ) ;
2022-11-25 23:14:08 +00:00
auto type_identifier = generator . intern_identifier ( " type " ) ;
auto value_identifier = generator . intern_identifier ( " value " ) ;
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
2023-07-14 21:57:49 +01:00
// 1. Let generatorKind be GetGeneratorKind().
// NOTE: is_in_async_generator_function differentiates the generator kind.
2022-12-09 18:48:57 +00:00
// 2. Let exprRef be ? Evaluation of AssignmentExpression.
// 3. Let value be ? GetValue(exprRef).
VERIFY ( m_argument ) ;
2024-02-04 08:00:54 +01:00
auto value = TRY ( m_argument - > generate_bytecode ( generator ) ) . value ( ) ;
2022-12-09 18:48:57 +00:00
// 4. Let iteratorRecord be ? GetIterator(value, generatorKind).
2024-05-07 21:36:56 +02:00
auto iterator_record = generator . allocate_register ( ) ;
2023-07-14 21:57:49 +01:00
auto iterator_hint = generator . is_in_async_generator_function ( ) ? IteratorHint : : Async : IteratorHint : : Sync ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetIterator > ( iterator_record , value , iterator_hint ) ;
2022-12-09 18:48:57 +00:00
// 5. Let iterator be iteratorRecord.[[Iterator]].
2024-05-07 21:36:56 +02:00
auto iterator = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetObjectFromIteratorRecord > ( iterator , iterator_record ) ;
2022-12-09 18:48:57 +00:00
// Cache iteratorRecord.[[NextMethod]] for use in step 7.a.i.
2024-05-07 21:36:56 +02:00
auto next_method = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetNextMethodFromIteratorRecord > ( next_method , iterator_record ) ;
2022-12-09 18:48:57 +00:00
// 6. Let received be NormalCompletion(undefined).
// See get_received_completion_type_and_value above.
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( received_completion_type , generator . add_constant ( Value ( to_underlying ( Completion : : Type : : Normal ) ) ) ) ;
2022-12-09 18:48:57 +00:00
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( received_completion_value , generator . add_constant ( js_undefined ( ) ) ) ;
2022-12-09 18:48:57 +00:00
// 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 ( ) ;
2024-05-07 21:36:56 +02:00
auto received_completion_type_register_is_normal = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyEquals > (
received_completion_type_register_is_normal ,
received_completion_type ,
generator . add_constant ( Value ( to_underlying ( Completion : : Type : : Normal ) ) ) ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
received_completion_type_register_is_normal ,
2022-12-09 18:48:57 +00:00
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]] »).
2024-05-07 21:36:56 +02:00
auto array = generator . allocate_register ( ) ;
2024-05-08 12:43:08 +02:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : NewArray > ( 1 , array , ReadonlySpan < ScopedOperand > { & received_completion_value , 1 } ) ;
2024-05-07 21:36:56 +02:00
auto inner_result = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : CallWithArgumentArray > ( Bytecode : : Op : : CallType : : Call , inner_result , next_method , iterator , array ) ;
2022-12-09 18:48:57 +00:00
2023-07-14 21:57:49 +01:00
// ii. If generatorKind is async, set innerResult to ? Await(innerResult).
2024-02-04 08:00:54 +01:00
if ( generator . is_in_async_generator_function ( ) ) {
auto new_inner_result = generate_await ( generator , inner_result , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
generator . emit < Bytecode : : Op : : Mov > ( inner_result , new_inner_result ) ;
}
2022-12-09 18:48:57 +00:00
// iii. If innerResult is not an Object, throw a TypeError exception.
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ThrowIfNotObject > ( inner_result ) ;
2022-12-09 18:48:57 +00:00
// iv. Let done be ? IteratorComplete(innerResult).
2024-05-07 21:36:56 +02:00
auto done = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_iterator_complete ( done , inner_result ) ;
2022-12-09 18:48:57 +00:00
// 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 ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
done ,
2022-12-09 18:48:57 +00:00
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).
2024-05-07 21:36:56 +02:00
auto return_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_iterator_value ( return_value , inner_result ) ;
2022-12-09 18:48:57 +00:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_end_block } ) ;
generator . switch_to_basic_block ( type_is_normal_not_done_block ) ;
2023-07-14 21:57:49 +01:00
// vi. If generatorKind is async, set received to Completion(AsyncGeneratorYield(? IteratorValue(innerResult))).
2022-12-09 18:48:57 +00:00
// vii. Else, set received to Completion(GeneratorYield(innerResult)).
2024-02-04 08:00:54 +01:00
{
// 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.
// This only matters for non-async generators.
2024-05-07 21:36:56 +02:00
auto current_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_iterator_value ( current_value , inner_result ) ;
2024-05-06 22:38:43 +02:00
if ( is_in_finalizer ) {
saved_exception = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( Bytecode : : Operand ( * saved_exception ) , Bytecode : : Operand ( Bytecode : : Register : : exception ( ) ) ) ;
}
2024-02-04 08:00:54 +01:00
generate_yield ( generator ,
Bytecode : : Label { continuation_block } ,
current_value ,
received_completion ,
received_completion_type ,
received_completion_value ,
type_identifier ,
value_identifier ,
AwaitBeforeYield : : No ) ;
}
2022-12-09 18:48:57 +00:00
// 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 ( ) ;
2024-05-07 21:36:56 +02:00
auto received_completion_type_register_is_throw = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyEquals > (
received_completion_type_register_is_throw ,
2024-05-07 21:36:56 +02:00
received_completion_type ,
2024-02-04 08:00:54 +01:00
generator . add_constant ( Value ( to_underlying ( Completion : : Type : : Throw ) ) ) ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
received_completion_type_register_is_throw ,
2022-12-09 18:48:57 +00:00
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").
2024-05-07 21:36:56 +02:00
auto throw_method = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetMethod > ( throw_method , iterator , generator . intern_identifier ( " throw " ) ) ;
2022-12-09 18:48:57 +00:00
// 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 ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : JumpUndefined > (
throw_method ,
Bytecode : : Label { throw_method_is_undefined_block } ,
Bytecode : : Label { throw_method_is_defined_block } ) ;
2022-12-09 18:48:57 +00:00
generator . switch_to_basic_block ( throw_method_is_defined_block ) ;
// 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
2024-05-07 21:36:56 +02:00
auto received_value_array = generator . allocate_register ( ) ;
2024-05-08 12:43:08 +02:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : NewArray > ( 1 , received_value_array , ReadonlySpan < ScopedOperand > { & received_completion_value , 1 } ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : CallWithArgumentArray > ( Bytecode : : Op : : CallType : : Call , inner_result , throw_method , iterator , received_value_array ) ;
2022-12-09 18:48:57 +00:00
2023-07-14 21:57:49 +01:00
// 2. If generatorKind is async, set innerResult to ? Await(innerResult).
2024-02-04 08:00:54 +01:00
if ( generator . is_in_async_generator_function ( ) ) {
auto new_result = generate_await ( generator , inner_result , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
generator . emit < Bytecode : : Op : : Mov > ( inner_result , new_result ) ;
}
2022-12-09 18:48:57 +00:00
// 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.
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ThrowIfNotObject > ( inner_result ) ;
2022-12-09 18:48:57 +00:00
// 5. Let done be ? IteratorComplete(innerResult).
2024-02-04 08:00:54 +01:00
generator . emit_iterator_complete ( done , inner_result ) ;
2022-12-09 18:48:57 +00:00
// 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 ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
done ,
2022-12-09 18:48:57 +00:00
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).
2024-02-04 08:00:54 +01:00
generator . emit_iterator_value ( return_value , inner_result ) ;
2022-12-09 18:48:57 +00:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_end_block } ) ;
generator . switch_to_basic_block ( type_is_throw_not_done_block ) ;
2024-02-04 08:00:54 +01:00
{
// 7. If generatorKind is async, set received to Completion(AsyncGeneratorYield(? IteratorValue(innerResult))).
// 8. Else, set received to Completion(GeneratorYield(innerResult)).
2022-12-09 18:48:57 +00:00
2024-02-04 08:00:54 +01:00
// 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.
// This only matters for non-async generators.
2024-05-07 21:36:56 +02:00
auto yield_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_iterator_value ( yield_value , inner_result ) ;
generate_yield ( generator , Bytecode : : Label { continuation_block } , yield_value , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier , AwaitBeforeYield : : No ) ;
}
2022-12-09 18:48:57 +00:00
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 }.
2023-07-14 21:57:49 +01:00
// 3. If generatorKind is async, perform ? AsyncIteratorClose(iteratorRecord, closeCompletion).
if ( generator . is_in_async_generator_function ( ) ) {
// FIXME: This performs `await` outside of the generator!
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : AsyncIteratorClose > ( iterator_record , Completion : : Type : : Normal , Optional < Value > { } ) ;
2023-07-14 21:57:49 +01:00
}
// 4. Else, perform ? IteratorClose(iteratorRecord, closeCompletion).
else {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : IteratorClose > ( iterator_record , Completion : : Type : : Normal , Optional < Value > { } ) ;
2023-07-14 21:57:49 +01:00
}
2022-12-09 18:48:57 +00:00
// 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.
2024-05-07 21:36:56 +02:00
auto exception = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : NewTypeError > ( exception , generator . intern_string ( ErrorType : : YieldFromIteratorMissingThrowMethod . message ( ) ) ) ;
2022-12-09 18:48:57 +00:00
generator . perform_needed_unwinds < Bytecode : : Op : : Throw > ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Throw > ( exception ) ;
2022-12-09 18:48:57 +00:00
// c. Else,
// i. Assert: received.[[Type]] is return.
generator . switch_to_basic_block ( type_is_return_block ) ;
// ii. Let return be ? GetMethod(iterator, "return").
2024-05-07 21:36:56 +02:00
auto return_method = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetMethod > ( return_method , iterator , generator . intern_identifier ( " return " ) ) ;
2022-12-09 18:48:57 +00:00
// iii. If return is undefined, then
auto & return_is_undefined_block = generator . make_block ( ) ;
auto & return_is_defined_block = generator . make_block ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : JumpUndefined > (
return_method ,
2022-12-09 18:48:57 +00:00
Bytecode : : Label { return_is_undefined_block } ,
Bytecode : : Label { return_is_defined_block } ) ;
generator . switch_to_basic_block ( return_is_undefined_block ) ;
2023-07-14 21:57:49 +01:00
// 1. If generatorKind is async, set received.[[Value]] to ? Await(received.[[Value]]).
2024-02-04 08:00:54 +01:00
if ( generator . is_in_async_generator_function ( ) ) {
generate_await ( generator , received_completion_value , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
}
2023-07-14 21:57:49 +01:00
2022-12-09 18:48:57 +00:00
// 2. Return ? received.
// NOTE: This will always be a return completion.
generator . perform_needed_unwinds < Bytecode : : Op : : Yield > ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Yield > ( nullptr , received_completion_value ) ;
2022-12-09 18:48:57 +00:00
generator . switch_to_basic_block ( return_is_defined_block ) ;
// iv. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »).
2024-05-07 21:36:56 +02:00
auto call_array = generator . allocate_register ( ) ;
2024-05-08 12:43:08 +02:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : NewArray > ( 1 , call_array , ReadonlySpan < ScopedOperand > { & received_completion_value , 1 } ) ;
2024-05-07 21:36:56 +02:00
auto inner_return_result = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : CallWithArgumentArray > ( Bytecode : : Op : : CallType : : Call , inner_return_result , return_method , iterator , call_array ) ;
2022-12-09 18:48:57 +00:00
2023-07-14 21:57:49 +01:00
// v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
2024-02-04 08:00:54 +01:00
if ( generator . is_in_async_generator_function ( ) ) {
auto new_value = generate_await ( generator , inner_return_result , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
generator . emit < Bytecode : : Op : : Mov > ( inner_return_result , new_value ) ;
}
2022-12-09 18:48:57 +00:00
// vi. If innerReturnResult is not an Object, throw a TypeError exception.
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ThrowIfNotObject > ( inner_return_result ) ;
2022-12-09 18:48:57 +00:00
// vii. Let done be ? IteratorComplete(innerReturnResult).
2024-02-04 08:00:54 +01:00
generator . emit_iterator_complete ( done , inner_return_result ) ;
2022-12-09 18:48:57 +00:00
// 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 ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
done ,
2022-12-09 18:48:57 +00:00
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).
2024-05-07 21:36:56 +02:00
auto inner_return_result_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_iterator_value ( inner_return_result_value , inner_return_result ) ;
2022-12-09 18:48:57 +00:00
// 2. Return Completion Record { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
generator . perform_needed_unwinds < Bytecode : : Op : : Yield > ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Yield > ( nullptr , inner_return_result_value ) ;
2022-12-09 18:48:57 +00:00
generator . switch_to_basic_block ( type_is_return_not_done_block ) ;
2023-07-14 21:57:49 +01:00
// ix. If generatorKind is async, set received to Completion(AsyncGeneratorYield(? IteratorValue(innerReturnResult))).
2022-12-09 18:48:57 +00:00
// x. Else, set received to Completion(GeneratorYield(innerReturnResult)).
// 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.
2023-07-14 21:57:49 +01:00
// This only matters for non-async generators.
2024-05-07 21:36:56 +02:00
auto received = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_iterator_value ( received , inner_return_result ) ;
2022-12-09 18:48:57 +00:00
2024-02-04 08:00:54 +01:00
generate_yield ( generator , Bytecode : : Label { continuation_block } , received , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier , AwaitBeforeYield : : No ) ;
2022-12-09 18:48:57 +00:00
generator . switch_to_basic_block ( continuation_block ) ;
2024-05-06 22:38:43 +02:00
if ( is_in_finalizer )
generator . emit < Bytecode : : Op : : Mov > ( Bytecode : : Operand ( Bytecode : : Register : : exception ( ) ) , Bytecode : : Operand ( * saved_exception ) ) ;
2024-05-07 21:36:56 +02:00
generator . emit < Bytecode : : Op : : Mov > ( received_completion , generator . accumulator ( ) ) ;
2024-02-04 08:00:54 +01:00
get_received_completion_type_and_value ( generator , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
2022-12-09 18:48:57 +00:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_block } ) ;
generator . switch_to_basic_block ( loop_end_block ) ;
2024-02-04 08:00:54 +01:00
return return_value ;
2022-02-12 19:54:08 +03:30
}
2021-06-14 15:46:41 +04:30
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > argument ;
2021-06-11 01:38:30 +04:30
if ( m_argument )
2024-02-04 08:00:54 +01:00
argument = TRY ( m_argument - > generate_bytecode ( generator ) ) . value ( ) ;
2022-11-25 23:14:27 +00:00
else
2024-02-04 08:00:54 +01:00
argument = generator . add_constant ( js_undefined ( ) ) ;
2021-06-11 01:38:30 +04:30
auto & continuation_block = generator . make_block ( ) ;
2024-05-06 22:38:43 +02:00
if ( is_in_finalizer ) {
saved_exception = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( Bytecode : : Operand ( * saved_exception ) , Bytecode : : Operand ( Bytecode : : Register : : exception ( ) ) ) ;
}
2024-02-04 08:00:54 +01:00
generate_yield ( generator , Bytecode : : Label { continuation_block } , * argument , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier , AwaitBeforeYield : : Yes ) ;
2021-06-11 01:38:30 +04:30
generator . switch_to_basic_block ( continuation_block ) ;
2024-05-06 22:38:43 +02:00
if ( is_in_finalizer )
generator . emit < Bytecode : : Op : : Mov > ( Bytecode : : Operand ( Bytecode : : Register : : exception ( ) ) , Bytecode : : Operand ( * saved_exception ) ) ;
2024-05-07 21:36:56 +02:00
generator . emit < Bytecode : : Op : : Mov > ( received_completion , generator . accumulator ( ) ) ;
2024-02-04 08:00:54 +01:00
get_received_completion_type_and_value ( generator , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
2022-11-25 23:14:08 +00:00
auto & normal_completion_continuation_block = generator . make_block ( ) ;
auto & throw_completion_continuation_block = generator . make_block ( ) ;
2024-05-07 21:36:56 +02:00
auto received_completion_type_is_normal = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyEquals > (
received_completion_type_is_normal ,
received_completion_type ,
generator . add_constant ( Value ( to_underlying ( Completion : : Type : : Normal ) ) ) ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
received_completion_type_is_normal ,
2022-11-25 23:14:08 +00:00
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 ) ;
2024-05-07 21:36:56 +02:00
auto received_completion_type_is_throw = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyEquals > (
received_completion_type_is_throw ,
received_completion_type ,
generator . add_constant ( Value ( to_underlying ( Completion : : Type : : Throw ) ) ) ) ;
2022-11-25 23:14:08 +00:00
// If type is not equal to "throw" or "normal", assume it's "return".
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
received_completion_type_is_throw ,
2022-11-25 23:14:08 +00:00
Bytecode : : Label { throw_value_block } ,
Bytecode : : Label { return_value_block } ) ;
generator . switch_to_basic_block ( throw_value_block ) ;
generator . perform_needed_unwinds < Bytecode : : Op : : Throw > ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Throw > ( received_completion_value ) ;
2022-11-25 23:14:08 +00:00
generator . switch_to_basic_block ( return_value_block ) ;
generator . perform_needed_unwinds < Bytecode : : Op : : Yield > ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Yield > ( nullptr , received_completion_value ) ;
2022-11-25 23:14:08 +00:00
generator . switch_to_basic_block ( normal_completion_continuation_block ) ;
2024-02-04 08:00:54 +01:00
return received_completion_value ;
2021-06-05 15:53:36 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > IfStatement : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-06 13:26:50 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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 ( ) ;
2023-09-28 12:46:17 +02:00
auto & end_block = generator . make_block ( ) ;
2021-06-09 06:49:58 +04:30
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : Mov > ( dst , generator . add_constant ( js_undefined ( ) ) ) ;
auto predicate = TRY ( m_predicate - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
predicate ,
2021-06-09 06:49:58 +04:30
Bytecode : : Label { true_block } ,
Bytecode : : Label { false_block } ) ;
generator . switch_to_basic_block ( true_block ) ;
2024-02-04 08:00:54 +01:00
auto consequent = TRY ( m_consequent - > generate_bytecode ( generator , dst ) ) ;
2023-09-28 12:43:11 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
2024-02-04 08:00:54 +01:00
if ( consequent . has_value ( ) )
generator . emit < Bytecode : : Op : : Mov > ( dst , * consequent ) ;
2023-09-28 12:46:17 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
2023-09-28 12:43:11 +02:00
}
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( false_block ) ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > alternate ;
2024-02-04 08:00:54 +01:00
if ( m_alternate ) {
alternate = TRY ( m_alternate - > generate_bytecode ( generator , dst ) ) ;
}
if ( ! generator . is_current_block_terminated ( ) ) {
if ( alternate . has_value ( ) )
generator . emit < Bytecode : : Op : : Mov > ( dst , * alternate ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
2024-02-04 08:00:54 +01:00
}
2021-06-09 06:49:58 +04:30
2021-06-20 12:38:59 +02:00
generator . switch_to_basic_block ( end_block ) ;
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-06 13:26:50 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ContinueStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-06 13:33:02 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-01-24 13:32:02 -05:00
if ( ! m_target_label . has_value ( ) ) {
2022-11-25 16:35:39 +01:00
generator . generate_continue ( ) ;
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2022-06-11 23:09:37 +01:00
}
2024-01-24 13:32:02 -05:00
generator . generate_continue ( m_target_label . value ( ) ) ;
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2021-06-06 13:33:02 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > DebuggerStatement : : generate_bytecode ( Bytecode : : Generator & , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-07 20:05:50 +01:00
{
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2021-06-07 20:05:50 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ConditionalExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-08 04:54:34 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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 ( ) ;
2024-02-04 08:00:54 +01:00
auto test = TRY ( m_test - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
test ,
2021-06-09 06:49:58 +04:30
Bytecode : : Label { true_block } ,
Bytecode : : Label { false_block } ) ;
2021-06-08 04:54:34 +01:00
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( true_block ) ;
2024-02-04 08:00:54 +01:00
auto consequent = TRY ( m_consequent - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( dst , consequent ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( 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 ) ;
2024-02-04 08:00:54 +01:00
auto alternate = TRY ( m_alternate - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( dst , alternate ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( 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 ) ;
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-08 04:54:34 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > SequenceExpression : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-08 10:13:37 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > last_value ;
2024-02-04 08:00:54 +01:00
for ( auto & expression : m_expressions ) {
last_value = TRY ( expression - > generate_bytecode ( generator ) ) ;
}
2022-02-12 19:54:08 +03:30
2024-02-04 08:00:54 +01:00
return last_value ;
2021-06-08 10:13:37 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > TemplateLiteral : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-08 19:14:01 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
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 + + ) {
2024-02-04 08:00:54 +01:00
auto value = TRY ( m_expressions [ i ] - > generate_bytecode ( generator ) ) . value ( ) ;
2021-06-07 20:58:36 -07:00
if ( i = = 0 ) {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( dst , value ) ;
2021-06-07 20:58:36 -07:00
} else {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ConcatString > ( dst , value ) ;
2021-06-07 20:58:36 -07:00
}
2021-06-08 19:14:01 +02:00
}
2021-06-09 21:11:04 +02:00
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-08 19:14:01 +02:00
}
2021-06-09 11:40:38 +02:00
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > TaggedTemplateLiteral : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-06-09 21:02:24 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto tag = TRY ( m_tag - > generate_bytecode ( generator ) ) . value ( ) ;
2021-06-09 22:07:18 +02:00
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
2024-05-07 21:36:56 +02:00
Vector < ScopedOperand > string_regs ;
2021-06-09 21:02:24 +02:00
auto & expressions = m_template_literal - > expressions ( ) ;
2022-03-14 14:48:42 +00:00
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
2024-05-08 12:43:08 +02:00
auto string_reg = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
if ( is < NullLiteral > ( expressions [ i ] ) ) {
generator . emit < Bytecode : : Op : : Mov > ( string_reg , generator . add_constant ( js_undefined ( ) ) ) ;
} else {
auto value = TRY ( expressions [ i ] - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( string_reg , value ) ;
}
2024-05-08 12:43:08 +02:00
string_regs . append ( move ( string_reg ) ) ;
2021-06-09 21:02:24 +02:00
}
2024-05-08 12:43:08 +02:00
auto strings_array = generator . allocate_register ( ) ;
2022-03-14 14:48:42 +00:00
if ( string_regs . is_empty ( ) ) {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : NewArray > ( strings_array ) ;
2022-03-14 14:48:42 +00:00
} else {
2024-05-08 12:43:08 +02:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : NewArray > ( string_regs . size ( ) , strings_array , string_regs ) ;
2022-03-14 14:48:42 +00:00
}
2021-06-09 21:02:24 +02:00
2024-05-07 21:36:56 +02:00
Vector < ScopedOperand > argument_regs ;
2024-02-04 08:00:54 +01:00
argument_regs . append ( strings_array ) ;
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 ) {
2024-05-08 12:43:08 +02:00
auto string_reg = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
auto string = TRY ( expressions [ i ] - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( string_reg , string ) ;
2024-05-08 12:43:08 +02:00
argument_regs . append ( move ( string_reg ) ) ;
2021-06-09 21:02:24 +02:00
}
2024-05-07 21:36:56 +02:00
Vector < ScopedOperand > raw_string_regs ;
2024-05-08 12:43:08 +02:00
raw_string_regs . ensure_capacity ( m_template_literal - > raw_strings ( ) . size ( ) ) ;
2021-06-09 21:02:24 +02:00
for ( auto & raw_string : m_template_literal - > raw_strings ( ) ) {
2024-02-04 08:00:54 +01:00
auto value = TRY ( raw_string - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-08 12:43:08 +02:00
auto raw_string_reg = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( raw_string_reg , value ) ;
2024-05-08 12:43:08 +02:00
raw_string_regs . append ( move ( raw_string_reg ) ) ;
2021-06-09 21:02:24 +02:00
}
2024-05-07 21:36:56 +02:00
auto raw_strings_array = generator . allocate_register ( ) ;
2022-03-14 14:48:42 +00:00
if ( raw_string_regs . is_empty ( ) ) {
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : NewArray > ( raw_strings_array ) ;
2022-03-14 14:48:42 +00:00
} else {
2024-05-08 12:43:08 +02:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : NewArray > ( raw_string_regs . size ( ) , raw_strings_array , raw_string_regs ) ;
2022-03-14 14:48:42 +00:00
}
2021-06-09 21:02:24 +02:00
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : PutById > ( strings_array , generator . intern_identifier ( " raw " ) , raw_strings_array , Bytecode : : Op : : PropertyKind : : KeyValue , generator . next_property_lookup_cache ( ) ) ;
2021-06-09 21:02:24 +02:00
2024-05-07 21:36:56 +02:00
auto arguments = generator . allocate_register ( ) ;
2022-09-07 23:39:43 +02:00
if ( ! argument_regs . is_empty ( ) )
2024-05-08 12:43:08 +02:00
generator . emit_with_extra_operand_slots < Bytecode : : Op : : NewArray > ( argument_regs . size ( ) , arguments , argument_regs ) ;
2022-09-07 23:39:43 +02:00
else
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : NewArray > ( arguments ) ;
2022-09-07 23:39:43 +02:00
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : CallWithArgumentArray > ( Bytecode : : Op : : CallType : : Call , dst , tag , generator . add_constant ( js_undefined ( ) ) , arguments ) ;
return dst ;
2021-06-09 21:02:24 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > UpdateExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > ) const
2021-06-09 11:40:38 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto reference = TRY ( generator . emit_load_from_reference ( * m_argument ) ) ;
2021-06-09 11:40:38 +02:00
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > previous_value_for_postfix ;
2021-06-09 11:40:38 +02:00
2024-02-20 11:45:01 +01:00
if ( m_op = = UpdateOp : : Increment ) {
if ( m_prefixed ) {
generator . emit < Bytecode : : Op : : Increment > ( * reference . loaded_value ) ;
} else {
2024-05-07 21:36:56 +02:00
previous_value_for_postfix = generator . allocate_register ( ) ;
2024-02-20 11:45:01 +01:00
generator . emit < Bytecode : : Op : : PostfixIncrement > ( * previous_value_for_postfix , * reference . loaded_value ) ;
}
} else {
if ( m_prefixed ) {
generator . emit < Bytecode : : Op : : Decrement > ( * reference . loaded_value ) ;
} else {
2024-05-07 21:36:56 +02:00
previous_value_for_postfix = generator . allocate_register ( ) ;
2024-02-20 11:45:01 +01:00
generator . emit < Bytecode : : Op : : PostfixDecrement > ( * previous_value_for_postfix , * reference . loaded_value ) ;
}
}
2021-06-09 11:40:38 +02:00
2024-02-04 08:00:54 +01:00
if ( is < Identifier > ( * m_argument ) )
( void ) TRY ( generator . emit_store_to_reference ( static_cast < Identifier const & > ( * m_argument ) , * reference . loaded_value ) ) ;
2023-10-04 15:22:07 +02:00
else
2024-02-04 08:00:54 +01:00
( void ) TRY ( generator . emit_store_to_reference ( reference , * reference . loaded_value ) ) ;
2021-06-09 11:40:38 +02:00
2021-10-25 15:17:41 +02:00
if ( ! m_prefixed )
2024-02-04 08:00:54 +01:00
return * previous_value_for_postfix ;
return * reference . loaded_value ;
2021-06-09 11:40:38 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ThrowStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-09 18:18:56 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto argument = TRY ( m_argument - > generate_bytecode ( generator ) ) . value ( ) ;
2022-03-14 02:26:39 +00:00
generator . perform_needed_unwinds < Bytecode : : Op : : Throw > ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Throw > ( argument ) ;
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2021-06-09 18:18:56 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > BreakStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-10 20:28:43 +08:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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
2024-01-24 13:32:02 -05:00
if ( ! m_target_label . has_value ( ) ) {
2022-11-25 16:15:34 +01:00
generator . generate_break ( ) ;
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2022-06-11 23:09:37 +01:00
}
2024-01-24 13:32:02 -05:00
generator . generate_break ( m_target_label . value ( ) ) ;
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2021-06-10 20:28:43 +08:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > TryStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-10 15:04:38 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2021-06-10 15:04:38 +02:00
auto & saved_block = generator . current_block ( ) ;
Optional < Bytecode : : Label > handler_target ;
Optional < Bytecode : : Label > finalizer_target ;
2023-10-19 23:18:54 +02:00
Optional < Bytecode : : Generator : : UnwindContext > unwind_context ;
2021-06-10 15:04:38 +02:00
Bytecode : : BasicBlock * next_block { nullptr } ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > dst ;
2024-02-04 08:00:54 +01:00
2021-06-10 15:04:38 +02:00
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 > ( ) ;
2024-04-11 11:58:18 +02:00
generator . start_boundary ( Bytecode : : Generator : : BlockBoundaryType : : LeaveFinally ) ;
2024-02-04 08:00:54 +01:00
( void ) TRY ( m_finalizer - > generate_bytecode ( generator ) ) ;
2024-04-11 11:58:18 +02:00
generator . end_boundary ( Bytecode : : Generator : : BlockBoundaryType : : LeaveFinally ) ;
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
generator . start_boundary ( Bytecode : : Generator : : BlockBoundaryType : : ReturnToFinally ) ;
2023-10-19 23:18:54 +02:00
unwind_context . emplace ( generator , finalizer_target ) ;
}
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
2024-05-07 21:36:56 +02:00
auto caught_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Catch > ( caught_value ) ;
2023-11-11 23:19:46 +01:00
2024-04-11 11:07:35 +02:00
if ( ! m_finalizer ) {
2022-11-13 20:56:53 +01:00
generator . emit < Bytecode : : Op : : LeaveUnwindContext > ( ) ;
2024-04-11 11:07:35 +02:00
generator . emit < Bytecode : : Op : : RestoreScheduledJump > ( ) ;
}
2022-11-13 20:56:53 +01:00
2023-09-25 14:11:27 +02:00
// OPTIMIZATION: We avoid creating a lexical environment if the catch clause has no parameter.
bool did_create_variable_scope_for_catch_clause = false ;
2024-02-04 08:00:54 +01:00
TRY ( m_handler - > parameter ( ) . visit (
[ & ] ( DeprecatedFlyString const & parameter ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-10-24 22:46:54 +02:00
if ( ! parameter . is_empty ( ) ) {
2023-09-25 14:11:27 +02:00
generator . begin_variable_scope ( ) ;
did_create_variable_scope_for_catch_clause = true ;
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 ) ;
2024-05-11 18:28:03 +02:00
generator . emit < Bytecode : : Op : : SetVariable > ( parameter_identifier , caught_value , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
2021-07-11 15:15:38 +04:30
}
2024-02-04 08:00:54 +01:00
return { } ;
2021-07-11 15:15:38 +04:30
} ,
2024-02-04 08:00:54 +01:00
[ & ] ( NonnullRefPtr < BindingPattern const > const & binding_pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
2023-09-25 14:11:27 +02:00
generator . begin_variable_scope ( ) ;
did_create_variable_scope_for_catch_clause = true ;
2024-05-09 05:00:07 +00:00
TRY ( binding_pattern - > generate_bytecode ( generator , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , caught_value , true ) ) ;
2024-02-04 08:00:54 +01:00
return { } ;
2022-02-12 19:54:08 +03:30
} ) ) ;
2021-07-11 15:15:38 +04:30
2024-02-04 08:00:54 +01:00
auto handler_result = TRY ( m_handler - > body ( ) . generate_bytecode ( generator ) ) ;
if ( handler_result . has_value ( ) & & ! generator . is_current_block_terminated ( ) ) {
2024-05-07 21:36:56 +02:00
dst = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( * dst , * handler_result ) ;
}
2021-06-10 15:04:38 +02:00
handler_target = Bytecode : : Label { handler_block } ;
2023-09-25 14:11:27 +02:00
if ( did_create_variable_scope_for_catch_clause )
generator . end_variable_scope ( ) ;
2022-03-14 02:38:13 +00:00
2021-06-10 15:04:38 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
if ( m_finalizer ) {
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( * finalizer_target ) ;
2021-06-10 15:04:38 +02:00
} else {
VERIFY ( ! next_block ) ;
2023-10-19 23:18:54 +02:00
VERIFY ( ! unwind_context . has_value ( ) ) ;
2021-06-10 15:04:38 +02:00
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 ) ;
2023-10-19 23:18:54 +02:00
if ( m_handler ) {
2024-04-11 00:25:54 +02:00
if ( ! m_finalizer ) {
auto const * parent_unwind_context = generator . current_unwind_context ( ) ;
if ( parent_unwind_context )
unwind_context . emplace ( generator , parent_unwind_context - > finalizer ( ) ) ;
else
unwind_context . emplace ( generator , OptionalNone ( ) ) ;
}
2023-10-19 23:18:54 +02:00
unwind_context - > set_handler ( handler_target . value ( ) ) ;
}
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 ) ;
2024-03-06 08:36:19 +01:00
generator . emit < Bytecode : : Op : : EnterUnwindContext > ( Bytecode : : Label { target_block } ) ;
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 ) ;
2024-02-04 08:00:54 +01:00
auto block_result = TRY ( m_block - > generate_bytecode ( generator ) ) ;
2021-11-10 22:22:26 +03:30
if ( ! generator . is_current_block_terminated ( ) ) {
2024-02-04 08:00:54 +01:00
if ( block_result . has_value ( ) ) {
2024-05-07 21:36:56 +02:00
dst = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( * dst , * block_result ) ;
}
2021-11-10 22:22:26 +03:30
if ( m_finalizer ) {
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( * finalizer_target ) ;
2021-11-10 22:22:26 +03:30
} else {
2023-10-19 23:18:54 +02:00
VERIFY ( unwind_context . has_value ( ) ) ;
unwind_context . clear ( ) ;
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 ) ;
2024-02-04 08:00:54 +01:00
if ( ! dst . has_value ( ) )
return generator . add_constant ( js_undefined ( ) ) ;
return dst ;
2021-06-10 15:04:38 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > SwitchStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-06-11 23:09:37 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-06-11 23:09:37 +01:00
return generate_labelled_evaluation ( generator , { } ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > SwitchStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-11 00:36:16 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-05-07 21:36:56 +02:00
auto dst = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Mov > ( dst , generator . add_constant ( js_undefined ( ) ) ) ;
2024-02-04 08:00:54 +01:00
auto discriminant = TRY ( m_discriminant - > generate_bytecode ( generator ) ) . value ( ) ;
2021-06-11 00:36:16 +02:00
Vector < Bytecode : : BasicBlock & > case_blocks ;
2023-06-28 11:45:19 +02:00
Bytecode : : BasicBlock * entry_block_for_default { nullptr } ;
2021-06-11 00:36:16 +02:00
Bytecode : : BasicBlock * next_test_block = & generator . make_block ( ) ;
2022-04-03 02:13:51 +04:30
2024-05-11 13:25:08 +02:00
bool did_create_lexical_environment = false ;
if ( has_lexical_declarations ( ) )
did_create_lexical_environment = generator . emit_block_declaration_instantiation ( * this ) ;
2022-04-03 02:13:51 +04:30
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { * next_test_block } ) ;
2022-04-03 02:13:51 +04:30
2024-05-08 13:08:38 +02:00
Queue < Bytecode : : BasicBlock * > test_blocks ;
for ( auto & switch_case : m_cases ) {
if ( switch_case - > test ( ) )
test_blocks . enqueue ( & generator . make_block ( ) ) ;
}
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 ) ;
2024-02-04 08:00:54 +01:00
auto test_value = TRY ( switch_case - > test ( ) - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-07 21:36:56 +02:00
auto result = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyEquals > ( result , test_value , discriminant ) ;
2024-05-08 13:08:38 +02:00
next_test_block = test_blocks . dequeue ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
result ,
2024-05-08 12:55:32 +02:00
Bytecode : : Label { case_block } ,
2023-09-28 12:43:11 +02:00
Bytecode : : Label { * next_test_block } ) ;
2021-06-11 00:36:16 +02:00
} else {
2024-05-08 12:55:32 +02:00
entry_block_for_default = & case_block ;
2021-06-11 00:36:16 +02:00
}
2023-06-28 11:45:19 +02:00
2021-06-11 00:36:16 +02:00
case_blocks . append ( case_block ) ;
}
generator . switch_to_basic_block ( * next_test_block ) ;
auto & end_block = generator . make_block ( ) ;
2023-06-28 11:45:19 +02:00
if ( entry_block_for_default ! = nullptr ) {
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { * entry_block_for_default } ) ;
2021-06-11 00:36:16 +02:00
} else {
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
2021-06-11 00:36:16 +02:00
}
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 ) ;
2023-03-06 14:17:01 +01:00
for ( auto & statement : switch_case - > children ( ) ) {
2024-02-04 08:00:54 +01:00
auto result = TRY ( statement - > generate_bytecode ( generator ) ) ;
2022-03-15 01:43:44 +00:00
if ( generator . is_current_block_terminated ( ) )
break ;
2024-02-04 08:00:54 +01:00
if ( result . has_value ( ) )
generator . emit < Bytecode : : Op : : Mov > ( dst , * result ) ;
else
generator . emit < Bytecode : : Op : : Mov > ( dst , generator . add_constant ( js_undefined ( ) ) ) ;
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 ( ) ) {
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
2021-06-11 00:36:16 +02:00
} else {
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { * next_block } ) ;
2021-06-11 00:36:16 +02:00
}
}
current_block + + ;
}
generator . end_breakable_scope ( ) ;
generator . switch_to_basic_block ( end_block ) ;
2023-06-25 07:37:24 +02:00
2024-05-11 13:25:08 +02:00
if ( did_create_lexical_environment )
2023-06-25 07:37:24 +02:00
generator . end_variable_scope ( ) ;
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-11 00:36:16 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > SuperExpression : : generate_bytecode ( Bytecode : : Generator & , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2023-07-06 17:16:20 -04:00
{
// The semantics for SuperExpression are handled in CallExpression and SuperCall.
VERIFY_NOT_REACHED ( ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ClassDeclaration : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2021-06-30 15:42:13 -03:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto value = TRY ( m_class_expression - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit_set_variable ( * m_class_expression . ptr ( ) - > m_name , value , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
// NOTE: ClassDeclaration does not produce a value.
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2022-02-12 19:55:40 +03:30
}
2023-06-28 18:22:27 +03:00
// 15.7.14 Runtime Semantics: ClassDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ClassExpression : : generate_bytecode_with_lhs_name ( Bytecode : : Generator & generator , Optional < Bytecode : : IdentifierTableIndex > lhs_name , Optional < ScopedOperand > preferred_dst ) const
2022-02-12 19:55:40 +03:30
{
2023-06-28 18:22:27 +03:00
// NOTE: Step 2 is not a part of NewClass instruction because it is assumed to be done before super class expression evaluation
generator . emit < Bytecode : : Op : : CreateLexicalEnvironment > ( ) ;
if ( has_name ( ) | | ! lhs_name . has_value ( ) ) {
// NOTE: Step 3.a is not a part of NewClass instruction because it is assumed to be done before super class expression evaluation
2023-06-30 16:51:39 +03:00
auto interned_index = generator . intern_identifier ( name ( ) ) ;
2023-06-28 18:22:27 +03:00
generator . emit < Bytecode : : Op : : CreateVariable > ( interned_index , Bytecode : : Op : : EnvironmentMode : : Lexical , true ) ;
}
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > super_class ;
2023-06-28 18:22:27 +03:00
if ( m_super_class )
2024-02-04 08:00:54 +01:00
super_class = TRY ( m_super_class - > generate_bytecode ( generator ) ) . value ( ) ;
2023-06-28 18:22:27 +03:00
2024-05-11 22:54:41 +00:00
generator . emit < Op : : CreatePrivateEnvironment > ( ) ;
for ( auto const & element : m_elements ) {
auto opt_private_name = element - > private_bound_identifier ( ) ;
if ( opt_private_name . has_value ( ) ) {
generator . emit < Op : : AddPrivateName > ( generator . intern_identifier ( * opt_private_name ) ) ;
}
}
Vector < Optional < ScopedOperand > > elements ;
for ( auto const & element : m_elements ) {
Optional < ScopedOperand > key ;
if ( is < ClassMethod > ( * element ) ) {
auto const & class_method = static_cast < ClassMethod const & > ( * element ) ;
if ( ! is < PrivateIdentifier > ( class_method . key ( ) ) )
key = TRY ( class_method . key ( ) . generate_bytecode ( generator ) ) ;
} else if ( is < ClassField > ( * element ) ) {
auto const & class_field = static_cast < ClassField const & > ( * element ) ;
if ( ! is < PrivateIdentifier > ( class_field . key ( ) ) )
key = TRY ( class_field . key ( ) . generate_bytecode ( generator ) ) ;
}
elements . append ( { key } ) ;
}
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
2024-05-11 22:54:41 +00:00
generator . emit_with_extra_slots < Op : : NewClass , Optional < Operand > > ( elements . size ( ) , dst , super_class . has_value ( ) ? super_class - > operand ( ) : Optional < Operand > { } , * this , lhs_name , elements ) ;
generator . emit < Op : : LeavePrivateEnvironment > ( ) ;
2023-06-28 18:22:27 +03:00
2024-02-04 08:00:54 +01:00
return dst ;
2021-06-30 15:42:13 -03:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ClassExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2023-06-23 14:27:42 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
return generate_bytecode_with_lhs_name ( generator , { } , preferred_dst ) ;
2023-06-23 14:27:42 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > SpreadExpression : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-09-02 23:39:04 +02:00
{
// 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 ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ThisExpression : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2021-10-24 14:43:00 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-05-07 12:16:37 +02:00
return generator . get_this ( preferred_dst ) ;
2021-10-24 14:43:00 +02:00
}
2024-05-07 21:36:56 +02:00
static ScopedOperand generate_await (
2024-02-04 08:00:54 +01:00
Bytecode : : Generator & generator ,
2024-05-07 21:36:56 +02:00
ScopedOperand argument ,
ScopedOperand received_completion ,
ScopedOperand received_completion_type ,
ScopedOperand received_completion_value ,
2024-02-04 08:00:54 +01:00
Bytecode : : IdentifierTableIndex type_identifier ,
Bytecode : : IdentifierTableIndex value_identifier )
2021-11-11 00:46:07 +03:30
{
VERIFY ( generator . is_in_async_function ( ) ) ;
auto & continuation_block = generator . make_block ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Await > ( Bytecode : : Label { continuation_block } , argument ) ;
2021-11-11 00:46:07 +03:30
generator . switch_to_basic_block ( continuation_block ) ;
2022-12-25 17:15:29 +01:00
2024-02-04 08:00:54 +01:00
// FIXME: It's really magical that we can just assume that the completion value is in register 0.
// It ends up there because we "return" from the Await instruction above via the synthetic
// generator function that actually drives async execution.
2024-05-07 21:36:56 +02:00
generator . emit < Bytecode : : Op : : Mov > ( received_completion , generator . accumulator ( ) ) ;
2024-02-04 08:00:54 +01:00
get_received_completion_type_and_value ( generator , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
2022-12-25 17:15:29 +01:00
auto & normal_completion_continuation_block = generator . make_block ( ) ;
auto & throw_value_block = generator . make_block ( ) ;
2024-05-07 21:36:56 +02:00
auto received_completion_type_is_normal = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : StrictlyEquals > (
received_completion_type_is_normal ,
received_completion_type ,
generator . add_constant ( Value ( to_underlying ( Completion : : Type : : Normal ) ) ) ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
received_completion_type_is_normal ,
2022-12-25 17:15:29 +01:00
Bytecode : : Label { normal_completion_continuation_block } ,
Bytecode : : Label { throw_value_block } ) ;
2023-07-14 21:57:49 +01:00
// Simplification: The only abrupt completion we receive from AsyncFunctionDriverWrapper or AsyncGenerator is Type::Throw
2022-12-25 17:15:29 +01:00
// So we do not need to account for the Type::Return path
generator . switch_to_basic_block ( throw_value_block ) ;
generator . perform_needed_unwinds < Bytecode : : Op : : Throw > ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Throw > ( received_completion_value ) ;
2022-12-25 17:15:29 +01:00
generator . switch_to_basic_block ( normal_completion_continuation_block ) ;
2024-02-04 08:00:54 +01:00
return received_completion_value ;
2023-06-27 19:24:34 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > AwaitExpression : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2023-06-27 19:24:34 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto argument = TRY ( m_argument - > generate_bytecode ( generator ) ) . value ( ) ;
2024-05-07 21:36:56 +02:00
auto received_completion = generator . allocate_register ( ) ;
auto received_completion_type = generator . allocate_register ( ) ;
auto received_completion_value = generator . allocate_register ( ) ;
2023-07-14 21:57:49 +01:00
2024-05-07 21:36:56 +02:00
generator . emit < Bytecode : : Op : : Mov > ( received_completion , generator . accumulator ( ) ) ;
2023-07-14 21:57:49 +01:00
auto type_identifier = generator . intern_identifier ( " type " ) ;
auto value_identifier = generator . intern_identifier ( " value " ) ;
2024-02-04 08:00:54 +01:00
return generate_await ( generator , argument , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
2021-11-11 00:46:07 +03:30
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > WithStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-03-13 16:01:18 +03:30
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto object = TRY ( m_object - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : EnterObjectEnvironment > ( object ) ;
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 ) ;
2023-07-02 10:28:36 +02:00
2024-02-04 08:00:54 +01:00
auto body_result = TRY ( m_body - > generate_bytecode ( generator ) ) ;
if ( ! body_result . has_value ( ) )
body_result = generator . add_constant ( js_undefined ( ) ) ;
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
2024-02-04 08:00:54 +01:00
return body_result ;
2022-03-13 16:01:18 +03:30
}
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 } ;
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > iterator ;
2022-03-18 20:18:19 +03:30
} ;
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 ;
2023-06-28 09:07:33 +02:00
if ( variable_declaration . declaration_kind ( ) = = DeclarationKind : : Var ) {
// B.3.5 Initializers in ForIn Statement Heads, https://tc39.es/ecma262/#sec-initializers-in-forin-statement-heads
auto & variable = variable_declaration . declarations ( ) . first ( ) ;
if ( variable - > init ( ) ) {
VERIFY ( variable - > target ( ) . has < NonnullRefPtr < Identifier const > > ( ) ) ;
2023-07-05 02:17:10 +02:00
auto identifier = variable - > target ( ) . get < NonnullRefPtr < Identifier const > > ( ) ;
auto identifier_table_ref = generator . intern_identifier ( identifier - > string ( ) ) ;
2024-02-04 08:00:54 +01:00
auto value = TRY ( generator . emit_named_evaluation_if_anonymous_function ( * variable - > init ( ) , identifier_table_ref ) ) . value ( ) ;
generator . emit_set_variable ( * identifier , value ) ;
2023-06-28 09:07:33 +02:00
}
} else {
2023-07-13 21:30:36 +02:00
auto has_non_local_variables = false ;
MUST ( variable_declaration . for_each_bound_identifier ( [ & ] ( auto const & identifier ) {
if ( ! identifier . is_local ( ) )
has_non_local_variables = true ;
2023-02-27 22:13:37 +00:00
} ) ) ;
2023-07-13 21:30:36 +02:00
if ( has_non_local_variables ) {
// 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
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
// NOTE: Nothing in the callback throws an exception.
MUST ( variable_declaration . for_each_bound_identifier ( [ & ] ( auto const & identifier ) {
if ( identifier . is_local ( ) )
return ;
// i. Perform ! newEnv.CreateMutableBinding(name, false).
auto interned_identifier = generator . intern_identifier ( identifier . string ( ) ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( interned_identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
} ) ) ;
// d. Set the running execution context's LexicalEnvironment to newEnv.
// 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.
2024-02-04 08:00:54 +01:00
auto object = TRY ( rhs - > generate_bytecode ( generator ) ) . value ( ) ;
2022-10-19 17:42:54 +02:00
// 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
2024-05-07 21:36:56 +02:00
auto iterator = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
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 ( ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : JumpNullish > (
2024-02-04 08:00:54 +01:00
object ,
2023-09-28 12:43:11 +02:00
Bytecode : : Label { nullish_block } ,
Bytecode : : Label { continuation_block } ) ;
2022-10-19 17:42:54 +02:00
// 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 }.
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetObjectPropertyIterator > ( iterator , object ) ;
2022-10-19 17:42:54 +02:00
}
// 7. Else,
else {
2022-03-18 20:18:19 +03:30
// a. Assert: iterationKind is iterate or async-iterate.
2023-07-18 14:52:21 -04:00
// b. If iterationKind is async-iterate, let iteratorKind be async.
// c. Else, let iteratorKind be sync.
auto iterator_kind = iteration_kind = = IterationKind : : AsyncIterate ? IteratorHint : : Async : IteratorHint : : Sync ;
2022-03-18 20:18:19 +03:30
2023-07-18 14:52:21 -04:00
// d. Return ? GetIterator(exprValue, iteratorKind).
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : GetIterator > ( iterator , object , iterator_kind ) ;
2022-03-18 20:18:19 +03:30
}
2024-02-04 08:00:54 +01:00
result . iterator = iterator ;
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
2024-05-07 21:36:56 +02:00
static Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > 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 , [[maybe_unused]] Optional < ScopedOperand > preferred_dst = { } )
2022-03-18 20:18:19 +03:30
{
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.
2024-05-07 21:36:56 +02:00
auto completion_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( completion_value , generator . add_constant ( js_undefined ( ) ) ) ;
2022-03-18 20:18:19 +03:30
// 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]]).
2024-05-07 21:36:56 +02:00
auto next_result = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : IteratorNext > ( next_result , * head_result . iterator ) ;
2022-03-18 20:18:19 +03:30
2023-06-27 19:24:34 +01:00
// b. If iteratorKind is async, set nextResult to ? Await(nextResult).
2023-07-14 21:57:49 +01:00
if ( iterator_kind = = IteratorHint : : Async ) {
2024-05-07 21:36:56 +02:00
auto received_completion = generator . allocate_register ( ) ;
auto received_completion_type = generator . allocate_register ( ) ;
auto received_completion_value = generator . allocate_register ( ) ;
2023-07-14 21:57:49 +01:00
auto type_identifier = generator . intern_identifier ( " type " ) ;
auto value_identifier = generator . intern_identifier ( " value " ) ;
2024-05-07 21:36:56 +02:00
generator . emit < Bytecode : : Op : : Mov > ( received_completion , generator . accumulator ( ) ) ;
2024-02-04 08:00:54 +01:00
auto new_result = generate_await ( generator , next_result , received_completion , received_completion_type , received_completion_value , type_identifier , value_identifier ) ;
generator . emit < Bytecode : : Op : : Mov > ( next_result , new_result ) ;
2023-07-14 21:57:49 +01:00
}
2022-03-18 20:18:19 +03:30
// c. If Type(nextResult) is not Object, throw a TypeError exception.
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : ThrowIfNotObject > ( next_result ) ;
2022-03-18 20:18:19 +03:30
// d. Let done be ? IteratorComplete(nextResult).
2024-05-07 21:36:56 +02:00
auto done = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_iterator_complete ( done , next_result ) ;
2022-03-18 20:18:19 +03:30
// e. If done is true, return V.
auto & loop_continue = generator . make_block ( ) ;
2024-05-09 15:13:31 +02:00
generator . emit_jump_if (
2024-02-04 08:00:54 +01:00
done ,
2023-09-28 12:43:11 +02:00
Bytecode : : Label { loop_end } ,
Bytecode : : Label { loop_continue } ) ;
2022-03-18 20:18:19 +03:30
generator . switch_to_basic_block ( loop_continue ) ;
// f. Let nextValue be ? IteratorValue(nextResult).
2024-05-07 21:36:56 +02:00
auto next_value = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
generator . emit_iterator_value ( next_value , next_result ) ;
2022-03-18 20:18:19 +03:30
// 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 ) ;
2024-02-04 08:00:54 +01:00
TRY ( assign_value_to_variable_declarator ( generator , declaration . declarations ( ) . first ( ) , declaration , next_value ) ) ;
2022-03-18 20:18:19 +03:30
} else {
2023-02-19 22:07:52 +01:00
if ( auto ptr = lhs . get_pointer < NonnullRefPtr < ASTNode const > > ( ) ) {
2024-02-04 08:00:54 +01:00
TRY ( generator . emit_store_to_reference ( * * ptr , next_value ) ) ;
2022-03-31 03:09:36 +04:30
} else {
2023-02-19 22:07:52 +01:00
auto & binding_pattern = lhs . get < NonnullRefPtr < BindingPattern const > > ( ) ;
2024-05-09 05:00:07 +00:00
TRY ( binding_pattern - > generate_bytecode ( generator , Bytecode : : Op : : SetVariable : : InitializationMode : : Set , next_value , 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.
// 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.
2023-12-06 15:07:42 +01:00
auto has_non_local_variables = false ;
2023-07-13 21:30:36 +02:00
MUST ( variable_declaration . for_each_bound_identifier ( [ & ] ( auto const & identifier ) {
2023-12-06 15:07:42 +01:00
if ( ! identifier . is_local ( ) )
has_non_local_variables = true ;
2023-02-27 22:13:37 +00:00
} ) ) ;
2022-03-18 20:18:19 +03:30
2023-12-06 15:07:42 +01:00
if ( has_non_local_variables ) {
generator . begin_variable_scope ( ) ;
has_lexical_binding = true ;
MUST ( variable_declaration . for_each_bound_identifier ( [ & ] ( auto const & identifier ) {
if ( identifier . is_local ( ) )
return ;
auto interned_identifier = generator . intern_identifier ( identifier . string ( ) ) ;
// 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 > ( interned_identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , true , false , true ) ;
}
// b. Else,
else {
// i. Perform ! environment.CreateMutableBinding(name, false).
generator . emit < Bytecode : : Op : : CreateVariable > ( interned_identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
}
} ) ) ;
// 3. Return unused.
// NOTE: No need to do that as we've inlined this.
}
2022-03-18 20:18:19 +03:30
// 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-07-05 02:17:10 +02:00
auto lhs_name = variable_declaration . declarations ( ) . first ( ) - > target ( ) . get < NonnullRefPtr < Identifier const > > ( ) ;
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.
2024-02-04 08:00:54 +01:00
generator . emit_set_variable ( * lhs_name , next_value , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , Bytecode : : Op : : EnvironmentMode : : Lexical ) ;
2022-03-18 20:18:19 +03:30
}
}
// 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 > > ( ) ;
2024-05-09 05:00:07 +00:00
( void ) TRY ( binding_pattern - > generate_bytecode (
2024-02-04 08:00:54 +01:00
generator ,
head_result . lhs_kind = = LHSKind : : VarBinding ? Bytecode : : Op : : SetVariable : : InitializationMode : : Set : Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ,
next_value ,
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.
2024-02-04 08:00:54 +01:00
auto result = TRY ( body . generate_bytecode ( generator ) ) ;
2023-07-05 14:07:20 +02:00
2022-03-18 20:18:19 +03:30
// 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.
2024-02-04 08:00:54 +01:00
if ( ! generator . is_current_block_terminated ( ) ) {
if ( result . has_value ( ) )
generator . emit < Bytecode : : Op : : Mov > ( completion_value , * result ) ;
2023-09-28 12:43:11 +02:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_update } ) ;
2024-02-04 08:00:54 +01:00
}
2022-03-27 18:46:25 +01:00
2022-03-18 20:18:19 +03:30
generator . switch_to_basic_block ( loop_end ) ;
2024-02-04 08:00:54 +01:00
return completion_value ;
2022-03-18 20:18:19 +03:30
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ForInStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-06-11 23:09:37 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
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
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ForInStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) 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 ) ) ;
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
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ForOfStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2022-06-11 23:09:37 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-06-11 23:09:37 +01:00
return generate_labelled_evaluation ( generator , { } ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ForOfStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) 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 ) ) ;
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
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ForAwaitOfStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2023-06-27 19:24:34 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2023-06-27 19:24:34 +01:00
return generate_labelled_evaluation ( generator , { } ) ;
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ForAwaitOfStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < DeprecatedFlyString > const & label_set , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2023-06-27 19:24:34 +01:00
{
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 ) ) ;
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
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > MetaProperty : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2022-03-19 19:40:21 +00:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2022-03-19 19:40:21 +00:00
// NewTarget : new . target
if ( m_type = = MetaProperty : : Type : : NewTarget ) {
// 1. Return GetNewTarget().
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : GetNewTarget > ( dst ) ;
return dst ;
2022-03-19 19:40:21 +00:00
}
// ImportMeta : import . meta
if ( m_type = = MetaProperty : : Type : : ImportMeta ) {
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : GetImportMeta > ( dst ) ;
return dst ;
2022-03-19 19:40:21 +00:00
}
VERIFY_NOT_REACHED ( ) ;
}
2023-06-17 10:11:23 +02:00
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ClassFieldInitializerStatement : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2023-06-17 10:11:23 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto value = TRY ( generator . emit_named_evaluation_if_anonymous_function ( * m_expression , generator . intern_identifier ( m_class_field_identifier_name ) , preferred_dst ) ) ;
2023-06-17 10:11:23 +02:00
generator . perform_needed_unwinds < Bytecode : : Op : : Return > ( ) ;
2024-05-07 21:36:56 +02:00
generator . emit < Bytecode : : Op : : Return > ( value . has_value ( ) ? value - > operand ( ) : Optional < Operand > { } ) ;
2024-02-04 08:00:54 +01:00
return value ;
2023-06-17 10:11:23 +02:00
}
2024-05-07 21:36:56 +02:00
static Bytecode : : CodeGenerationErrorOr < void > generate_optional_chain ( Bytecode : : Generator & generator , OptionalChain const & optional_chain , ScopedOperand current_value , ScopedOperand current_base , [[maybe_unused]] Optional < ScopedOperand > preferred_dst )
2023-06-17 14:50:23 +01:00
{
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > new_current_value ;
2023-06-17 14:50:23 +01:00
if ( is < MemberExpression > ( optional_chain . base ( ) ) ) {
auto & member_expression = static_cast < MemberExpression const & > ( optional_chain . base ( ) ) ;
2024-02-04 08:00:54 +01:00
auto base_and_value = TRY ( get_base_and_value_from_member_expression ( generator , member_expression ) ) ;
new_current_value = base_and_value . value ;
generator . emit < Bytecode : : Op : : Mov > ( current_base , base_and_value . base ) ;
2023-06-17 14:50:23 +01:00
} else if ( is < OptionalChain > ( optional_chain . base ( ) ) ) {
auto & sub_optional_chain = static_cast < OptionalChain const & > ( optional_chain . base ( ) ) ;
2024-02-04 08:00:54 +01:00
TRY ( generate_optional_chain ( generator , sub_optional_chain , current_value , current_base ) ) ;
new_current_value = current_value ;
2023-06-17 14:50:23 +01:00
} else {
2024-02-04 08:00:54 +01:00
new_current_value = TRY ( optional_chain . base ( ) . generate_bytecode ( generator ) ) . value ( ) ;
2023-06-17 14:50:23 +01:00
}
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( current_value , * new_current_value ) ;
2023-06-17 14:50:23 +01:00
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 > (
2024-02-04 08:00:54 +01:00
current_value ,
2023-06-17 14:50:23 +01:00
Bytecode : : Label { load_undefined_and_jump_to_end_block } ,
Bytecode : : Label { not_nullish_block } ) ;
generator . switch_to_basic_block ( not_nullish_block ) ;
}
2024-02-04 08:00:54 +01:00
TRY ( reference . visit (
[ & ] ( OptionalChain : : Call const & call ) - > Bytecode : : CodeGenerationErrorOr < void > {
auto arguments = TRY ( arguments_to_array_for_call ( generator , call . arguments ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : CallWithArgumentArray > ( Bytecode : : Op : : CallType : : Call , current_value , current_value , current_base , arguments ) ;
generator . emit < Bytecode : : Op : : Mov > ( current_base , generator . add_constant ( js_undefined ( ) ) ) ;
return { } ;
2023-06-17 14:50:23 +01:00
} ,
2024-02-04 08:00:54 +01:00
[ & ] ( OptionalChain : : ComputedReference const & ref ) - > Bytecode : : CodeGenerationErrorOr < void > {
generator . emit < Bytecode : : Op : : Mov > ( current_base , current_value ) ;
auto property = TRY ( ref . expression - > generate_bytecode ( generator ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : GetByValue > ( current_value , current_value , property ) ;
return { } ;
2023-06-17 14:50:23 +01:00
} ,
2024-02-04 08:00:54 +01:00
[ & ] ( OptionalChain : : MemberReference const & ref ) - > Bytecode : : CodeGenerationErrorOr < void > {
generator . emit < Bytecode : : Op : : Mov > ( current_base , current_value ) ;
generator . emit_get_by_id ( current_value , current_value , generator . intern_identifier ( ref . identifier - > string ( ) ) ) ;
return { } ;
2023-06-17 14:50:23 +01:00
} ,
2024-02-04 08:00:54 +01:00
[ & ] ( OptionalChain : : PrivateMemberReference const & ref ) - > Bytecode : : CodeGenerationErrorOr < void > {
generator . emit < Bytecode : : Op : : Mov > ( current_base , current_value ) ;
generator . emit < Bytecode : : Op : : GetPrivateById > ( current_value , current_value , generator . intern_identifier ( ref . private_identifier - > string ( ) ) ) ;
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 ) ;
2024-02-04 08:00:54 +01:00
generator . emit < Bytecode : : Op : : Mov > ( current_value , generator . add_constant ( js_undefined ( ) ) ) ;
2023-06-17 14:50:23 +01:00
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { end_block } ) ;
generator . switch_to_basic_block ( end_block ) ;
2024-02-04 08:00:54 +01:00
return { } ;
2023-06-17 14:50:23 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > OptionalChain : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2023-06-17 14:50:23 +01:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-05-07 21:36:56 +02:00
auto current_base = generator . allocate_register ( ) ;
2024-02-04 08:00:54 +01:00
auto current_value = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : Mov > ( current_base , generator . add_constant ( js_undefined ( ) ) ) ;
TRY ( generate_optional_chain ( generator , * this , current_value , current_base ) ) ;
return current_value ;
2023-06-17 14:50:23 +01:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ImportCall : : generate_bytecode ( Bytecode : : Generator & generator , Optional < ScopedOperand > preferred_dst ) const
2023-06-24 15:22:16 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2024-02-04 08:00:54 +01:00
auto specifier = TRY ( m_specifier - > generate_bytecode ( generator ) ) . value ( ) ;
2023-06-24 15:22:16 +02:00
2024-05-07 21:36:56 +02:00
Optional < ScopedOperand > options ;
2023-06-24 15:22:16 +02:00
if ( m_options ) {
2024-02-04 08:00:54 +01:00
options = TRY ( m_options - > generate_bytecode ( generator ) ) . value ( ) ;
2023-06-24 15:22:16 +02:00
} else {
2024-02-04 08:00:54 +01:00
options = generator . add_constant ( js_undefined ( ) ) ;
2023-06-24 15:22:16 +02:00
}
2024-02-04 08:00:54 +01:00
auto dst = choose_dst ( generator , preferred_dst ) ;
generator . emit < Bytecode : : Op : : ImportCall > ( dst , specifier , * options ) ;
return dst ;
2023-06-24 15:22:16 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ExportStatement : : generate_bytecode ( Bytecode : : Generator & generator , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2023-06-24 16:07:43 +02:00
{
2023-09-01 16:53:55 +02:00
Bytecode : : Generator : : SourceLocationScope scope ( generator , * this ) ;
2023-06-24 16:07:43 +02:00
if ( ! is_default_export ( ) ) {
if ( m_statement ) {
return m_statement - > generate_bytecode ( generator ) ;
}
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2023-06-24 16:07:43 +02:00
}
VERIFY ( m_statement ) ;
if ( is < FunctionDeclaration > ( * m_statement ) | | is < ClassDeclaration > ( * m_statement ) ) {
return m_statement - > generate_bytecode ( generator ) ;
}
if ( is < ClassExpression > ( * m_statement ) ) {
2024-02-04 08:00:54 +01:00
auto value = TRY ( generator . emit_named_evaluation_if_anonymous_function ( static_cast < ClassExpression const & > ( * m_statement ) , generator . intern_identifier ( " default " sv ) ) ) . value ( ) ;
if ( ! static_cast < ClassExpression const & > ( * m_statement ) . has_name ( ) ) {
generator . emit < Bytecode : : Op : : SetVariable > (
generator . intern_identifier ( ExportStatement : : local_name_for_default ) ,
value ,
Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
}
2023-06-28 00:53:08 +02:00
2024-02-04 08:00:54 +01:00
return value ;
2023-06-24 16:07:43 +02:00
}
// ExportDeclaration : export default AssignmentExpression ;
VERIFY ( is < Expression > ( * m_statement ) ) ;
2024-02-04 08:00:54 +01:00
auto value = TRY ( generator . emit_named_evaluation_if_anonymous_function ( static_cast < Expression const & > ( * m_statement ) , generator . intern_identifier ( " default " sv ) ) ) . value ( ) ;
generator . emit < Bytecode : : Op : : SetVariable > (
generator . intern_identifier ( ExportStatement : : local_name_for_default ) ,
value ,
Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
return value ;
2023-06-24 16:07:43 +02:00
}
2024-05-07 21:36:56 +02:00
Bytecode : : CodeGenerationErrorOr < Optional < ScopedOperand > > ImportStatement : : generate_bytecode ( Bytecode : : Generator & , [[maybe_unused]] Optional < ScopedOperand > preferred_dst ) const
2023-06-27 20:46:41 +02:00
{
2024-05-07 21:36:56 +02:00
return Optional < ScopedOperand > { } ;
2023-06-27 20:46:41 +02:00
}
2021-06-04 11:31:13 +02:00
}