2021-06-04 11:31:13 +02:00
/*
* Copyright ( c ) 2021 , 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
*/
2021-06-11 00:36:16 +02:00
# include <AK/Format.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>
2021-06-04 11:31:13 +02:00
namespace JS {
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ASTNode : : generate_bytecode ( Bytecode : : Generator & ) const
2021-06-04 11:31:13 +02:00
{
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Missing generate_bytecode() " sv ,
} ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ScopeNode : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2022-02-12 19:48:45 +03:30
Optional < Bytecode : : CodeGenerationError > maybe_error ;
size_t pushed_scope_count = 0 ;
auto const failing_completion = Completion ( Completion : : Type : : Throw , { } , { } ) ;
2022-04-03 02:13:51 +04:30
// Note: SwitchStatement has its own codegen, but still calls into this function to handle the scoping of the switch body.
auto is_switch_statement = is < SwitchStatement > ( * this ) ;
if ( is < BlockStatement > ( * this ) | | is_switch_statement ) {
2022-02-12 19:48:45 +03:30
// Perform the steps of BlockDeclarationInstantiation.
if ( has_lexical_declarations ( ) ) {
generator . begin_variable_scope ( Bytecode : : Generator : : BindingMode : : Lexical , Bytecode : : Generator : : SurroundingScopeKind : : Block ) ;
pushed_scope_count + + ;
}
( void ) for_each_lexically_scoped_declaration ( [ & ] ( Declaration const & declaration ) - > ThrowCompletionOr < void > {
auto is_constant_declaration = declaration . is_constant_declaration ( ) ;
declaration . for_each_bound_name ( [ & ] ( auto const & name ) {
auto index = generator . intern_identifier ( name ) ;
2022-07-17 19:09:19 +01:00
// NOTE: BlockDeclarationInstantiation takes as input the new lexical environment that was created and checks if there is a binding for the current name only in this new scope.
// For example: `{ let a = 1; { let a = 2; } }`. The second `a` will shadow the first `a` instead of re-initializing or setting it.
if ( is_constant_declaration | | ! generator . has_binding_in_current_scope ( index ) ) {
2022-02-12 19:48:45 +03:30
generator . register_binding ( index ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( index , Bytecode : : Op : : EnvironmentMode : : Lexical , is_constant_declaration ) ;
}
} ) ;
if ( is < FunctionDeclaration > ( declaration ) ) {
auto & function_declaration = static_cast < FunctionDeclaration const & > ( declaration ) ;
auto const & name = function_declaration . name ( ) ;
auto index = generator . intern_identifier ( name ) ;
generator . emit < Bytecode : : Op : : NewFunction > ( function_declaration ) ;
2022-04-05 03:54:58 +04:30
generator . emit < Bytecode : : Op : : SetVariable > ( index , Bytecode : : Op : : SetVariable : : InitializationMode : : InitializeOrSet ) ;
2022-02-12 19:48:45 +03:30
}
return { } ;
} ) ;
2022-04-03 02:13:51 +04:30
if ( is_switch_statement )
return { } ;
2022-02-12 19:48:45 +03:30
} else if ( is < Program > ( * this ) ) {
// Perform the steps of GlobalDeclarationInstantiation.
generator . begin_variable_scope ( Bytecode : : Generator : : BindingMode : : Global , Bytecode : : Generator : : SurroundingScopeKind : : Global ) ;
pushed_scope_count + + ;
// 1. Let lexNames be the LexicallyDeclaredNames of script.
// 2. Let varNames be the VarDeclaredNames of script.
// 3. For each element name of lexNames, do
( void ) for_each_lexically_declared_name ( [ & ] ( auto const & name ) - > ThrowCompletionOr < void > {
auto identifier = generator . intern_identifier ( name ) ;
// a. If env.HasVarDeclaration(name) is true, throw a SyntaxError exception.
// b. If env.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
if ( generator . has_binding ( identifier ) ) {
// FIXME: Throw an actual SyntaxError instance.
generator . emit < Bytecode : : Op : : NewString > ( generator . intern_string ( String : : formatted ( " SyntaxError: toplevel variable already declared: {} " , name ) ) ) ;
generator . emit < Bytecode : : Op : : Throw > ( ) ;
return { } ;
}
2021-09-30 15:02:36 +02:00
2022-02-12 19:48:45 +03:30
// FIXME: c. If hasRestrictedGlobalProperty is true, throw a SyntaxError exception.
// d. If hasRestrictedGlobal is true, throw a SyntaxError exception.
return { } ;
} ) ;
// 4. For each element name of varNames, do
( void ) for_each_var_declared_name ( [ & ] ( auto const & name ) - > ThrowCompletionOr < void > {
auto identifier = generator . intern_identifier ( name ) ;
// a. If env.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
if ( generator . has_binding ( identifier ) ) {
// FIXME: Throw an actual SyntaxError instance.
generator . emit < Bytecode : : Op : : NewString > ( generator . intern_string ( String : : formatted ( " SyntaxError: toplevel variable already declared: {} " , name ) ) ) ;
generator . emit < Bytecode : : Op : : Throw > ( ) ;
}
return { } ;
} ) ;
// 5. Let varDeclarations be the VarScopedDeclarations of script.
// 6. Let functionsToInitialize be a new empty List.
Vector < FunctionDeclaration const & > functions_to_initialize ;
// 7. Let declaredFunctionNames be a new empty List.
HashTable < FlyString > declared_function_names ;
// 8. For each element d of varDeclarations, in reverse List order, do
( void ) for_each_var_function_declaration_in_reverse_order ( [ & ] ( FunctionDeclaration const & function ) - > ThrowCompletionOr < void > {
// a. If d is neither a VariableDeclaration nor a ForBinding nor a BindingIdentifier, then
// i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration.
// Note: This is checked in for_each_var_function_declaration_in_reverse_order.
// ii. NOTE: If there are multiple function declarations for the same name, the last declaration is used.
// iii. Let fn be the sole element of the BoundNames of d.
// iv. If fn is not an element of declaredFunctionNames, then
if ( declared_function_names . set ( function . name ( ) ) ! = AK : : HashSetResult : : InsertedNewEntry )
return { } ;
// FIXME: 1. Let fnDefinable be ? env.CanDeclareGlobalFunction(fn).
// FIXME: 2. If fnDefinable is false, throw a TypeError exception.
// 3. Append fn to declaredFunctionNames.
// Note: Already done in step iv. above.
// 4. Insert d as the first element of functionsToInitialize.
functions_to_initialize . prepend ( function ) ;
return { } ;
} ) ;
// 9. Let declaredVarNames be a new empty List.
HashTable < FlyString > declared_var_names ;
// 10. For each element d of varDeclarations, do
( void ) for_each_var_scoped_variable_declaration ( [ & ] ( Declaration const & declaration ) {
// a. If d is a VariableDeclaration, a ForBinding, or a BindingIdentifier, then
// Note: This is done in for_each_var_scoped_variable_declaration.
// i. For each String vn of the BoundNames of d, do
return declaration . for_each_bound_name ( [ & ] ( auto const & name ) - > ThrowCompletionOr < void > {
// 1. If vn is not an element of declaredFunctionNames, then
if ( declared_function_names . contains ( name ) )
return { } ;
// FIXME: a. Let vnDefinable be ? env.CanDeclareGlobalVar(vn).
// FIXME: b. If vnDefinable is false, throw a TypeError exception.
// c. If vn is not an element of declaredVarNames, then
// i. Append vn to declaredVarNames.
declared_var_names . set ( name ) ;
return { } ;
} ) ;
} ) ;
// 11. NOTE: No abnormal terminations occur after this algorithm step if the global object is an ordinary object. However, if the global object is a Proxy exotic object it may exhibit behaviours that cause abnormal terminations in some of the following steps.
// 12. NOTE: Annex B.3.2.2 adds additional steps at this point.
// 12. Let strict be IsStrict of script.
// 13. If strict is false, then
if ( ! verify_cast < Program > ( * this ) . is_strict_mode ( ) ) {
// a. Let declaredFunctionOrVarNames be the list-concatenation of declaredFunctionNames and declaredVarNames.
// b. For each FunctionDeclaration f that is directly contained in the StatementList of a Block, CaseClause, or DefaultClause Contained within script, do
( void ) for_each_function_hoistable_with_annexB_extension ( [ & ] ( FunctionDeclaration & function_declaration ) {
// i. Let F be StringValue of the BindingIdentifier of f.
auto & function_name = function_declaration . name ( ) ;
// ii. If replacing the FunctionDeclaration f with a VariableStatement that has F as a BindingIdentifier would not produce any Early Errors for script, then
// Note: This step is already performed during parsing and for_each_function_hoistable_with_annexB_extension so this always passes here.
// 1. If env.HasLexicalDeclaration(F) is false, then
auto index = generator . intern_identifier ( function_name ) ;
if ( generator . has_binding ( index , Bytecode : : Generator : : BindingMode : : Lexical ) )
return ;
// FIXME: a. Let fnDefinable be ? env.CanDeclareGlobalVar(F).
// b. If fnDefinable is true, then
// i. NOTE: A var binding for F is only instantiated here if it is neither a VarDeclaredName nor the name of another FunctionDeclaration.
// ii. If declaredFunctionOrVarNames does not contain F, then
if ( ! declared_function_names . contains ( function_name ) & & ! declared_var_names . contains ( function_name ) ) {
// i. Perform ? env.CreateGlobalVarBinding(F, false).
2022-07-17 19:06:44 +01:00
generator . emit < Bytecode : : Op : : CreateVariable > ( index , Bytecode : : Op : : EnvironmentMode : : Var , false , true ) ;
2022-02-12 19:48:45 +03:30
// ii. Append F to declaredFunctionOrVarNames.
declared_function_names . set ( function_name ) ;
}
// iii. When the FunctionDeclaration f is evaluated, perform the following steps in place of the FunctionDeclaration Evaluation algorithm provided in 15.2.6:
// i. Let genv be the running execution context's VariableEnvironment.
// ii. Let benv be the running execution context's LexicalEnvironment.
// iii. Let fobj be ! benv.GetBindingValue(F, false).
// iv. Perform ? genv.SetMutableBinding(F, fobj, false).
2022-05-02 20:54:39 +02:00
// v. Return unused.
2022-02-12 19:48:45 +03:30
function_declaration . set_should_do_additional_annexB_steps ( ) ;
} ) ;
}
2021-09-30 15:02:36 +02:00
2022-02-12 19:48:45 +03:30
// 15. For each element d of lexDeclarations, do
( void ) for_each_lexically_scoped_declaration ( [ & ] ( Declaration const & declaration ) - > ThrowCompletionOr < void > {
// a. NOTE: Lexically declared names are only instantiated here but not initialized.
// b. For each element dn of the BoundNames of d, do
return declaration . for_each_bound_name ( [ & ] ( auto const & name ) - > ThrowCompletionOr < void > {
auto identifier = generator . intern_identifier ( name ) ;
// i. If IsConstantDeclaration of d is true, then
generator . register_binding ( identifier ) ;
if ( declaration . is_constant_declaration ( ) ) {
// 1. Perform ? env.CreateImmutableBinding(dn, true).
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , true ) ;
} else {
// ii. Else,
// 1. Perform ? env.CreateMutableBinding(dn, false).
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
}
return { } ;
} ) ;
} ) ;
// 16. For each Parse Node f of functionsToInitialize, do
for ( auto & function_declaration : functions_to_initialize ) {
// FIXME: Do this more correctly.
// a. Let fn be the sole element of the BoundNames of f.
// b. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv.
generator . emit < Bytecode : : Op : : NewFunction > ( function_declaration ) ;
// c. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false).
auto const & name = function_declaration . name ( ) ;
auto index = generator . intern_identifier ( name ) ;
if ( ! generator . has_binding ( index ) ) {
generator . register_binding ( index , Bytecode : : Generator : : BindingMode : : Var ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( index , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
}
generator . emit < Bytecode : : Op : : SetVariable > ( index , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
}
// 17. For each String vn of declaredVarNames, do
2022-07-17 19:06:44 +01:00
for ( auto & var_name : declared_var_names ) {
// a. Perform ? env.CreateGlobalVarBinding(vn, false).
auto index = generator . intern_identifier ( var_name ) ;
generator . register_binding ( index , Bytecode : : Generator : : BindingMode : : Var ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( index , Bytecode : : Op : : EnvironmentMode : : Var , false , true ) ;
}
2022-02-12 19:48:45 +03:30
} else {
// Perform the steps of FunctionDeclarationInstantiation.
generator . begin_variable_scope ( Bytecode : : Generator : : BindingMode : : Var , Bytecode : : Generator : : SurroundingScopeKind : : Function ) ;
pushed_scope_count + + ;
if ( has_lexical_declarations ( ) ) {
generator . begin_variable_scope ( Bytecode : : Generator : : BindingMode : : Lexical , Bytecode : : Generator : : SurroundingScopeKind : : Function ) ;
pushed_scope_count + + ;
}
// FIXME: Implement this boi correctly.
( void ) for_each_lexically_scoped_declaration ( [ & ] ( Declaration const & declaration ) - > ThrowCompletionOr < void > {
auto is_constant_declaration = declaration . is_constant_declaration ( ) ;
declaration . for_each_bound_name ( [ & ] ( auto const & name ) {
auto index = generator . intern_identifier ( name ) ;
if ( is_constant_declaration | | ! generator . has_binding ( index ) ) {
generator . register_binding ( index ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( index , Bytecode : : Op : : EnvironmentMode : : Lexical , is_constant_declaration ) ;
}
} ) ;
if ( is < FunctionDeclaration > ( declaration ) ) {
auto & function_declaration = static_cast < FunctionDeclaration const & > ( declaration ) ;
if ( auto result = function_declaration . generate_bytecode ( generator ) ; result . is_error ( ) ) {
maybe_error = result . release_error ( ) ;
// To make `for_each_lexically_scoped_declaration` happy.
return failing_completion ;
}
auto const & name = function_declaration . name ( ) ;
auto index = generator . intern_identifier ( name ) ;
if ( ! generator . has_binding ( index ) ) {
generator . register_binding ( index ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( index , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
}
generator . emit < Bytecode : : Op : : SetVariable > ( index , Bytecode : : Op : : SetVariable : : InitializationMode : : InitializeOrSet ) ;
}
return { } ;
} ) ;
}
if ( maybe_error . has_value ( ) )
return maybe_error . release_value ( ) ;
2021-09-30 15:02:36 +02:00
2021-06-09 19:57:18 +02:00
for ( auto & child : children ( ) ) {
2022-02-12 19:54:08 +03:30
TRY ( child . generate_bytecode ( generator ) ) ;
2021-06-09 19:57:18 +02:00
if ( generator . is_current_block_terminated ( ) )
break ;
}
2022-02-12 19:54:08 +03:30
2022-02-12 19:48:45 +03:30
for ( size_t i = 0 ; i < pushed_scope_count ; + + i )
generator . end_variable_scope ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > EmptyStatement : : generate_bytecode ( Bytecode : : Generator & ) const
2021-06-07 20:47:26 +02:00
{
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 20:47:26 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ExpressionStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2022-02-12 19:54:08 +03:30
return m_expression - > generate_bytecode ( generator ) ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > BinaryExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( m_lhs - > generate_bytecode ( generator ) ) ;
2021-06-07 20:58:36 -07:00
auto lhs_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( lhs_reg ) ;
2021-06-04 11:31:13 +02:00
2022-02-12 19:54:08 +03:30
TRY ( m_rhs - > generate_bytecode ( generator ) ) ;
2021-06-04 11:31:13 +02:00
switch ( m_op ) {
case BinaryOp : : Addition :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Add > ( lhs_reg ) ;
break ;
2021-06-04 11:31:13 +02:00
case BinaryOp : : Subtraction :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Sub > ( lhs_reg ) ;
break ;
2021-06-07 19:17:20 +02:00
case BinaryOp : : Multiplication :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Mul > ( lhs_reg ) ;
break ;
2021-06-07 19:17:20 +02:00
case BinaryOp : : Division :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Div > ( lhs_reg ) ;
break ;
2021-06-07 19:37:23 +02:00
case BinaryOp : : Modulo :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Mod > ( lhs_reg ) ;
break ;
2021-06-07 19:37:23 +02:00
case BinaryOp : : Exponentiation :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Exp > ( lhs_reg ) ;
break ;
2021-06-07 19:57:38 +02:00
case BinaryOp : : GreaterThan :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : GreaterThan > ( lhs_reg ) ;
break ;
2021-06-07 19:57:38 +02:00
case BinaryOp : : GreaterThanEquals :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : GreaterThanEquals > ( lhs_reg ) ;
break ;
2021-06-04 12:03:57 +02:00
case BinaryOp : : LessThan :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LessThan > ( lhs_reg ) ;
break ;
2021-06-07 19:57:38 +02:00
case BinaryOp : : LessThanEquals :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LessThanEquals > ( lhs_reg ) ;
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : LooselyInequals :
generator . emit < Bytecode : : Op : : LooselyInequals > ( lhs_reg ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : LooselyEquals :
generator . emit < Bytecode : : Op : : LooselyEquals > ( lhs_reg ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : StrictlyInequals :
generator . emit < Bytecode : : Op : : StrictlyInequals > ( lhs_reg ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : StrictlyEquals :
generator . emit < Bytecode : : Op : : StrictlyEquals > ( lhs_reg ) ;
2021-06-07 20:58:36 -07:00
break ;
2021-06-07 19:16:04 +01:00
case BinaryOp : : BitwiseAnd :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : BitwiseAnd > ( lhs_reg ) ;
break ;
2021-06-07 19:16:04 +01:00
case BinaryOp : : BitwiseOr :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : BitwiseOr > ( lhs_reg ) ;
break ;
2021-06-07 19:16:04 +01:00
case BinaryOp : : BitwiseXor :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : BitwiseXor > ( lhs_reg ) ;
break ;
2021-06-07 20:14:12 +01:00
case BinaryOp : : LeftShift :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LeftShift > ( lhs_reg ) ;
break ;
2021-06-07 20:14:12 +01:00
case BinaryOp : : RightShift :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : RightShift > ( lhs_reg ) ;
break ;
2021-06-07 20:14:12 +01:00
case BinaryOp : : UnsignedRightShift :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : UnsignedRightShift > ( lhs_reg ) ;
break ;
2021-06-07 21:13:37 +01:00
case BinaryOp : : In :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : In > ( lhs_reg ) ;
break ;
2021-06-07 21:18:19 +01:00
case BinaryOp : : InstanceOf :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : InstanceOf > ( lhs_reg ) ;
break ;
2021-06-04 11:31:13 +02:00
default :
2021-06-07 21:18:19 +01:00
VERIFY_NOT_REACHED ( ) ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > LogicalExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 02:18:47 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( m_lhs - > generate_bytecode ( generator ) ) ;
2021-06-08 02:18:47 +02:00
2021-06-09 06:49:58 +04:30
// lhs
// jump op (true) end (false) rhs
// rhs
// jump always (true) end
// end
auto & rhs_block = generator . make_block ( ) ;
auto & end_block = generator . make_block ( ) ;
2021-06-08 02:18:47 +02:00
switch ( m_op ) {
case LogicalOp : : And :
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { rhs_block } ,
Bytecode : : Label { end_block } ) ;
2021-06-08 02:18:47 +02:00
break ;
case LogicalOp : : Or :
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { end_block } ,
Bytecode : : Label { rhs_block } ) ;
2021-06-08 02:18:47 +02:00
break ;
case LogicalOp : : NullishCoalescing :
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpNullish > ( ) . set_targets (
Bytecode : : Label { rhs_block } ,
Bytecode : : Label { end_block } ) ;
2021-06-08 02:18:47 +02:00
break ;
default :
VERIFY_NOT_REACHED ( ) ;
}
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( rhs_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_rhs - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { end_block } ,
{ } ) ;
generator . switch_to_basic_block ( end_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 02:18:47 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > UnaryExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-07 19:53:47 +01:00
{
2022-03-27 19:50:09 +01:00
if ( m_op = = UnaryOp : : Delete )
return generator . emit_delete_reference ( m_lhs ) ;
2022-06-11 23:12:22 +01:00
// Typeof needs some special handling for when the LHS is an Identifier. Namely, it shouldn't throw on unresolvable references, but instead return "undefined".
if ( m_op ! = UnaryOp : : Typeof )
TRY ( m_lhs - > generate_bytecode ( generator ) ) ;
2021-06-07 19:53:47 +01:00
switch ( m_op ) {
case UnaryOp : : BitwiseNot :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : BitwiseNot > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Not :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Not > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Plus :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : UnaryPlus > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Minus :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : UnaryMinus > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Typeof :
2022-06-11 23:12:22 +01:00
if ( is < Identifier > ( * m_lhs ) ) {
auto & identifier = static_cast < Identifier const & > ( * m_lhs ) ;
generator . emit < Bytecode : : Op : : TypeofVariable > ( generator . intern_identifier ( identifier . string ( ) ) ) ;
break ;
}
TRY ( m_lhs - > generate_bytecode ( generator ) ) ;
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : Typeof > ( ) ;
break ;
2021-06-07 19:53:47 +01:00
case UnaryOp : : Void :
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
break ;
2022-03-27 19:50:09 +01:00
case UnaryOp : : Delete : // Delete is implemented above.
2021-06-07 19:53:47 +01:00
default :
2022-03-27 19:50:09 +01:00
VERIFY_NOT_REACHED ( ) ;
2021-06-07 19:53:47 +01:00
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 19:53:47 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > NumericLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( m_value ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > BooleanLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-07 20:22:15 +02:00
{
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value ( m_value ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 20:22:15 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > NullLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-07 20:22:15 +02:00
{
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_null ( ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 20:22:15 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > BigIntLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 07:59:25 +02:00
{
2021-06-29 17:51:52 +03:00
generator . emit < Bytecode : : Op : : NewBigInt > ( Crypto : : SignedBigInteger : : from_base ( 10 , m_value . substring ( 0 , m_value . length ( ) - 1 ) ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 07:59:25 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > StringLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2021-06-09 10:02:01 +02:00
generator . emit < Bytecode : : Op : : NewString > ( generator . intern_string ( m_value ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > RegExpLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-19 17:17:40 -07:00
{
auto source_index = generator . intern_string ( m_pattern ) ;
auto flags_index = generator . intern_string ( m_flags ) ;
generator . emit < Bytecode : : Op : : NewRegExp > ( source_index , flags_index ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-19 17:17:40 -07:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > Identifier : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2021-10-24 15:34:30 +02:00
generator . emit < Bytecode : : Op : : GetVariable > ( generator . intern_identifier ( m_string ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > AssignmentExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 11:31:13 +02:00
{
2021-07-11 01:16:17 +04:30
// FIXME: Implement this for BindingPatterns too.
auto & lhs = m_lhs . get < NonnullRefPtr < Expression > > ( ) ;
2021-10-25 15:29:52 +02:00
if ( m_op = = AssignmentOp : : Assignment ) {
2022-02-12 19:54:08 +03:30
TRY ( m_rhs - > generate_bytecode ( generator ) ) ;
return generator . emit_store_to_reference ( lhs ) ;
2021-10-25 15:29:52 +02:00
}
2021-06-07 20:12:38 +01:00
2022-02-12 19:54:08 +03:30
TRY ( generator . emit_load_from_reference ( lhs ) ) ;
2021-06-07 20:12:38 +01:00
2021-10-25 15:29:52 +02:00
Bytecode : : BasicBlock * rhs_block_ptr { nullptr } ;
Bytecode : : BasicBlock * end_block_ptr { nullptr } ;
2021-06-07 20:12:38 +01:00
2021-10-25 15:29:52 +02:00
// Logical assignments short circuit.
if ( m_op = = AssignmentOp : : AndAssignment ) { // &&=
rhs_block_ptr = & generator . make_block ( ) ;
end_block_ptr = & generator . make_block ( ) ;
2021-06-09 21:14:31 +01:00
2021-10-25 15:29:52 +02:00
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { * rhs_block_ptr } ,
Bytecode : : Label { * end_block_ptr } ) ;
} else if ( m_op = = AssignmentOp : : OrAssignment ) { // ||=
rhs_block_ptr = & generator . make_block ( ) ;
end_block_ptr = & generator . make_block ( ) ;
2021-06-09 21:14:31 +01:00
2021-10-25 15:29:52 +02:00
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { * end_block_ptr } ,
Bytecode : : Label { * rhs_block_ptr } ) ;
} else if ( m_op = = AssignmentOp : : NullishAssignment ) { // ??=
rhs_block_ptr = & generator . make_block ( ) ;
end_block_ptr = & generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpNullish > ( ) . set_targets (
Bytecode : : Label { * rhs_block_ptr } ,
Bytecode : : Label { * end_block_ptr } ) ;
2021-06-04 11:31:13 +02:00
}
2021-10-25 15:29:52 +02:00
if ( rhs_block_ptr )
generator . switch_to_basic_block ( * rhs_block_ptr ) ;
// lhs_reg is a part of the rhs_block because the store isn't necessary
// if the logical assignment condition fails.
auto lhs_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( lhs_reg ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_rhs - > generate_bytecode ( generator ) ) ;
2021-10-25 15:29:52 +02:00
switch ( m_op ) {
case AssignmentOp : : AdditionAssignment :
generator . emit < Bytecode : : Op : : Add > ( lhs_reg ) ;
break ;
case AssignmentOp : : SubtractionAssignment :
generator . emit < Bytecode : : Op : : Sub > ( lhs_reg ) ;
break ;
case AssignmentOp : : MultiplicationAssignment :
generator . emit < Bytecode : : Op : : Mul > ( lhs_reg ) ;
break ;
case AssignmentOp : : DivisionAssignment :
generator . emit < Bytecode : : Op : : Div > ( lhs_reg ) ;
break ;
case AssignmentOp : : ModuloAssignment :
generator . emit < Bytecode : : Op : : Mod > ( lhs_reg ) ;
break ;
case AssignmentOp : : ExponentiationAssignment :
generator . emit < Bytecode : : Op : : Exp > ( lhs_reg ) ;
break ;
case AssignmentOp : : BitwiseAndAssignment :
generator . emit < Bytecode : : Op : : BitwiseAnd > ( lhs_reg ) ;
break ;
case AssignmentOp : : BitwiseOrAssignment :
generator . emit < Bytecode : : Op : : BitwiseOr > ( lhs_reg ) ;
break ;
case AssignmentOp : : BitwiseXorAssignment :
generator . emit < Bytecode : : Op : : BitwiseXor > ( lhs_reg ) ;
break ;
case AssignmentOp : : LeftShiftAssignment :
generator . emit < Bytecode : : Op : : LeftShift > ( lhs_reg ) ;
break ;
case AssignmentOp : : RightShiftAssignment :
generator . emit < Bytecode : : Op : : RightShift > ( lhs_reg ) ;
break ;
case AssignmentOp : : UnsignedRightShiftAssignment :
generator . emit < Bytecode : : Op : : UnsignedRightShift > ( lhs_reg ) ;
break ;
case AssignmentOp : : AndAssignment :
case AssignmentOp : : OrAssignment :
case AssignmentOp : : NullishAssignment :
break ; // These are handled above.
default :
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented operation " sv ,
} ;
2021-06-04 20:47:07 +02:00
}
2022-02-12 19:54:08 +03:30
TRY ( generator . emit_store_to_reference ( lhs ) ) ;
2021-10-25 15:29:52 +02:00
if ( end_block_ptr ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { * end_block_ptr } ,
{ } ) ;
generator . switch_to_basic_block ( * end_block_ptr ) ;
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 11:31:13 +02:00
}
2022-06-11 23:09:37 +01:00
// 14.13.3 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-labelled-statements-runtime-semantics-evaluation
// LabelledStatement : LabelIdentifier : LabelledItem
Bytecode : : CodeGenerationErrorOr < void > LabelledStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
// Return ? LabelledEvaluation of this LabelledStatement with argument « ».
return generate_labelled_evaluation ( generator , { } ) ;
}
// 14.13.4 Runtime Semantics: LabelledEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-labelledevaluation
// LabelledStatement : LabelIdentifier : LabelledItem
Bytecode : : CodeGenerationErrorOr < void > LabelledStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < FlyString > const & label_set ) const
{
// Convert the m_labelled_item NNRP to a reference early so we don't have to do it every single time we want to use it.
auto const & labelled_item = * m_labelled_item ;
// 1. Let label be the StringValue of LabelIdentifier.
// NOTE: Not necessary, this is m_label.
// 2. Let newLabelSet be the list-concatenation of labelSet and « label ».
// FIXME: Avoid copy here.
auto new_label_set = label_set ;
new_label_set . append ( m_label ) ;
// 3. Let stmtResult be LabelledEvaluation of LabelledItem with argument newLabelSet.
// NOTE: stmtResult will be in the accumulator after running the generated bytecode.
if ( is < IterationStatement > ( labelled_item ) ) {
auto const & iteration_statement = static_cast < IterationStatement const & > ( labelled_item ) ;
TRY ( iteration_statement . generate_labelled_evaluation ( generator , new_label_set ) ) ;
} else if ( is < SwitchStatement > ( labelled_item ) ) {
auto const & switch_statement = static_cast < SwitchStatement const & > ( labelled_item ) ;
TRY ( switch_statement . generate_labelled_evaluation ( generator , new_label_set ) ) ;
} else if ( is < LabelledStatement > ( labelled_item ) ) {
auto const & labelled_statement = static_cast < LabelledStatement const & > ( labelled_item ) ;
TRY ( labelled_statement . generate_labelled_evaluation ( generator , new_label_set ) ) ;
} else {
auto & labelled_break_block = generator . make_block ( ) ;
// NOTE: We do not need a continuable scope as `continue;` is not allowed outside of iteration statements, throwing a SyntaxError in the parser.
generator . begin_breakable_scope ( Bytecode : : Label { labelled_break_block } , new_label_set ) ;
TRY ( labelled_item . generate_bytecode ( generator ) ) ;
generator . end_breakable_scope ( ) ;
if ( ! generator . is_current_block_terminated ( ) ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { labelled_break_block } ,
{ } ) ;
}
generator . switch_to_basic_block ( labelled_break_block ) ;
}
// 4. If stmtResult.[[Type]] is break and SameValue(stmtResult.[[Target]], label) is true, then
// a. Set stmtResult to NormalCompletion(stmtResult.[[Value]]).
// NOTE: These steps are performed by making labelled break jump straight to the appropriate break block, which preserves the statement result's value in the accumulator.
// 5. Return Completion(stmtResult).
// NOTE: This is in the accumulator.
return { } ;
}
Bytecode : : CodeGenerationErrorOr < void > IterationStatement : : generate_labelled_evaluation ( Bytecode : : Generator & , Vector < FlyString > const & ) const
{
return Bytecode : : CodeGenerationError {
this ,
" Missing generate_labelled_evaluation() " sv ,
} ;
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > WhileStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
Bytecode : : CodeGenerationErrorOr < void > WhileStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < FlyString > const & label_set ) const
2021-06-04 12:07:38 +02:00
{
2021-06-09 06:49:58 +04:30
// test
// jump if_false (true) end (false) body
// body
// jump always (true) test
// end
auto & test_block = generator . make_block ( ) ;
auto & body_block = generator . make_block ( ) ;
auto & end_block = generator . make_block ( ) ;
// Init result register
2021-06-08 22:17:00 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
auto result_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( result_reg ) ;
2021-06-09 06:49:58 +04:30
// jump to the test block
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { test_block } ,
{ } ) ;
generator . switch_to_basic_block ( test_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_test - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { body_block } ,
Bytecode : : Label { end_block } ) ;
generator . switch_to_basic_block ( body_block ) ;
2022-06-11 23:09:37 +01:00
generator . begin_continuable_scope ( Bytecode : : Label { test_block } , label_set ) ;
generator . begin_breakable_scope ( Bytecode : : Label { end_block } , label_set ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
2022-03-14 02:13:33 +00:00
generator . end_breakable_scope ( ) ;
generator . end_continuable_scope ( ) ;
2021-06-09 19:57:18 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { test_block } ,
{ } ) ;
}
2022-02-12 19:54:08 +03:30
2022-06-30 14:29:43 +01:00
generator . switch_to_basic_block ( end_block ) ;
generator . emit < Bytecode : : Op : : Load > ( result_reg ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 12:07:38 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > DoWhileStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
Bytecode : : CodeGenerationErrorOr < void > DoWhileStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < FlyString > const & label_set ) const
2021-06-04 12:20:44 +02:00
{
2021-06-09 06:49:58 +04:30
// jump always (true) body
// test
// jump if_false (true) end (false) body
// body
// jump always (true) test
// end
auto & test_block = generator . make_block ( ) ;
auto & body_block = generator . make_block ( ) ;
auto & end_block = generator . make_block ( ) ;
// Init result register
2021-06-08 22:17:00 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
auto result_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( result_reg ) ;
2021-06-09 06:49:58 +04:30
// jump to the body block
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { body_block } ,
{ } ) ;
generator . switch_to_basic_block ( test_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_test - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { body_block } ,
Bytecode : : Label { end_block } ) ;
generator . switch_to_basic_block ( body_block ) ;
2022-06-11 23:09:37 +01:00
generator . begin_continuable_scope ( Bytecode : : Label { test_block } , label_set ) ;
generator . begin_breakable_scope ( Bytecode : : Label { end_block } , label_set ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
2022-03-14 02:13:33 +00:00
generator . end_breakable_scope ( ) ;
generator . end_continuable_scope ( ) ;
2021-06-09 19:57:18 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { test_block } ,
{ } ) ;
}
2022-02-12 19:54:08 +03:30
2022-06-30 14:29:43 +01:00
generator . switch_to_basic_block ( end_block ) ;
generator . emit < Bytecode : : Op : : Load > ( result_reg ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 12:20:44 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ForStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
Bytecode : : CodeGenerationErrorOr < void > ForStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < FlyString > const & label_set ) const
2021-06-08 10:54:40 +01:00
{
2021-06-09 06:49:58 +04:30
// init
// jump always (true) test
// test
// jump if_true (true) body (false) end
// body
// jump always (true) update
// update
// jump always (true) test
// end
// If 'test' is missing, fuse the 'test' and 'body' basic blocks
// If 'update' is missing, fuse the 'body' and 'update' basic blocks
Bytecode : : BasicBlock * test_block_ptr { nullptr } ;
Bytecode : : BasicBlock * body_block_ptr { nullptr } ;
Bytecode : : BasicBlock * update_block_ptr { nullptr } ;
auto & end_block = generator . make_block ( ) ;
2021-06-08 10:54:40 +01:00
2022-03-14 02:39:24 +00:00
bool has_lexical_environment = false ;
2022-06-11 23:09:37 +01:00
// The breakable scope needs to start here to unwind the potentially created lexical environment for the init bytecode.
generator . begin_breakable_scope ( Bytecode : : Label { end_block } , label_set ) ;
2022-03-14 02:39:24 +00:00
if ( m_init ) {
if ( m_init - > is_variable_declaration ( ) ) {
auto & variable_declaration = verify_cast < VariableDeclaration > ( * m_init ) ;
if ( variable_declaration . is_lexical_declaration ( ) ) {
has_lexical_environment = true ;
// FIXME: Is Block correct?
generator . begin_variable_scope ( Bytecode : : Generator : : BindingMode : : Lexical , Bytecode : : Generator : : SurroundingScopeKind : : Block ) ;
bool is_const = variable_declaration . is_constant_declaration ( ) ;
variable_declaration . for_each_bound_name ( [ & ] ( auto const & name ) {
auto index = generator . intern_identifier ( name ) ;
generator . register_binding ( index ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( index , Bytecode : : Op : : EnvironmentMode : : Lexical , is_const ) ;
} ) ;
}
}
2022-02-12 19:54:08 +03:30
TRY ( m_init - > generate_bytecode ( generator ) ) ;
2022-03-14 02:39:24 +00:00
}
2021-06-07 20:58:36 -07:00
2021-06-09 06:49:58 +04:30
body_block_ptr = & generator . make_block ( ) ;
if ( m_test )
test_block_ptr = & generator . make_block ( ) ;
else
test_block_ptr = body_block_ptr ;
if ( m_update )
update_block_ptr = & generator . make_block ( ) ;
else
update_block_ptr = body_block_ptr ;
2021-06-08 22:17:00 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
auto result_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( result_reg ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { * test_block_ptr } ,
{ } ) ;
2021-06-08 10:54:40 +01:00
if ( m_test ) {
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( * test_block_ptr ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_test - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { * body_block_ptr } ,
Bytecode : : Label { end_block } ) ;
2021-06-08 10:54:40 +01:00
}
2021-06-07 20:58:36 -07:00
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( * body_block_ptr ) ;
2022-06-11 23:09:37 +01:00
generator . begin_continuable_scope ( Bytecode : : Label { * update_block_ptr } , label_set ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
2021-06-08 10:54:40 +01:00
generator . end_continuable_scope ( ) ;
2021-06-09 06:49:58 +04:30
2021-06-09 19:57:18 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
if ( m_update ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { * update_block_ptr } ,
{ } ) ;
generator . switch_to_basic_block ( * update_block_ptr ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_update - > generate_bytecode ( generator ) ) ;
2021-06-09 19:57:18 +02:00
}
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
2021-06-09 19:57:18 +02:00
Bytecode : : Label { * test_block_ptr } ,
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 ) ;
generator . emit < Bytecode : : Op : : Load > ( result_reg ) ;
2022-03-15 01:44:32 +00:00
if ( has_lexical_environment )
generator . end_variable_scope ( ) ;
2022-06-11 23:09:37 +01:00
generator . end_breakable_scope ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 10:54:40 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ObjectExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 20:30:23 +02:00
{
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : NewObject > ( ) ;
2021-06-11 19:40:48 +03:00
if ( m_properties . is_empty ( ) )
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 20:30:23 +02:00
2021-06-11 19:40:48 +03:00
auto object_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( object_reg ) ;
for ( auto & property : m_properties ) {
2022-03-31 00:59:58 +04:30
Bytecode : : Op : : PropertyKind property_kind ;
switch ( property . type ( ) ) {
case ObjectProperty : : Type : : KeyValue :
property_kind = Bytecode : : Op : : PropertyKind : : KeyValue ;
break ;
case ObjectProperty : : Type : : Getter :
property_kind = Bytecode : : Op : : PropertyKind : : Getter ;
break ;
case ObjectProperty : : Type : : Setter :
property_kind = Bytecode : : Op : : PropertyKind : : Setter ;
break ;
case ObjectProperty : : Type : : Spread :
property_kind = Bytecode : : Op : : PropertyKind : : Spread ;
break ;
case ObjectProperty : : Type : : ProtoSetter :
property_kind = Bytecode : : Op : : PropertyKind : : ProtoSetter ;
break ;
}
2021-06-11 19:40:48 +03:00
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
2022-03-31 00:59:58 +04:30
if ( property_kind ! = Bytecode : : Op : : PropertyKind : : Spread )
TRY ( property . value ( ) . generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : PutById > ( object_reg , key_name , property_kind ) ;
2021-06-11 19:40:48 +03:00
} else {
2022-02-12 19:54:08 +03:30
TRY ( property . key ( ) . generate_bytecode ( generator ) ) ;
2021-06-11 19:40:48 +03:00
auto property_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( property_reg ) ;
2022-03-31 00:59:58 +04:30
if ( property_kind ! = Bytecode : : Op : : PropertyKind : : Spread )
TRY ( property . value ( ) . generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : PutByValue > ( object_reg , property_reg , property_kind ) ;
2021-06-11 19:40:48 +03:00
}
}
generator . emit < Bytecode : : Op : : Load > ( object_reg ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-04 20:30:23 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ArrayExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 23:06:52 +02:00
{
Vector < Bytecode : : Register > element_regs ;
2022-03-14 14:48:42 +00:00
for ( auto & element : m_elements ) {
if ( element & & is < SpreadExpression > ( * element ) ) {
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented element kind: SpreadExpression " sv ,
} ;
}
element_regs . append ( generator . allocate_register ( ) ) ;
}
size_t i = 0 ;
2021-06-08 23:06:52 +02:00
for ( auto & element : m_elements ) {
if ( element ) {
2022-02-12 19:54:08 +03:30
TRY ( element - > generate_bytecode ( generator ) ) ;
2021-06-08 23:06:52 +02:00
2022-03-14 14:48:42 +00:00
if ( is < SpreadExpression > ( * element ) )
VERIFY_NOT_REACHED ( ) ;
2021-06-09 04:43:13 +01:00
} else {
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value { } ) ;
2021-06-08 23:06:52 +02:00
}
2022-03-14 14:48:42 +00:00
auto & element_reg = element_regs [ i + + ] ;
2021-06-08 23:06:52 +02:00
generator . emit < Bytecode : : Op : : Store > ( element_reg ) ;
}
2022-03-14 14:48:42 +00:00
if ( element_regs . is_empty ( ) ) {
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
} else {
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2u , AK : : Array { element_regs . first ( ) , element_regs . last ( ) } ) ;
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 23:06:52 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > MemberExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-04 21:03:53 +02:00
{
2022-02-12 19:54:08 +03:30
return generator . emit_load_from_reference ( * this ) ;
2021-06-04 21:03:53 +02:00
}
2022-02-12 19:48:45 +03:30
Bytecode : : CodeGenerationErrorOr < void > FunctionDeclaration : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-05 15:15:30 +02:00
{
2022-02-12 19:48:45 +03:30
if ( m_is_hoisted ) {
auto index = generator . intern_identifier ( name ( ) ) ;
generator . emit < Bytecode : : Op : : GetVariable > ( index ) ;
2022-03-13 12:43:45 +03:30
generator . emit < Bytecode : : Op : : SetVariable > ( index , Bytecode : : Op : : SetVariable : : InitializationMode : : Set , Bytecode : : Op : : EnvironmentMode : : Var ) ;
2022-02-12 19:48:45 +03:30
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-05 15:15:30 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > FunctionExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-11 10:46:46 +02:00
{
2022-06-11 23:24:55 +01:00
bool has_name = ! name ( ) . is_empty ( ) ;
Optional < Bytecode : : IdentifierTableIndex > name_identifier ;
if ( has_name ) {
generator . begin_variable_scope ( Bytecode : : Generator : : BindingMode : : Lexical ) ;
name_identifier = generator . intern_identifier ( name ( ) ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( * name_identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , true ) ;
}
2021-06-11 10:46:46 +02:00
generator . emit < Bytecode : : Op : : NewFunction > ( * this ) ;
2022-06-11 23:24:55 +01:00
if ( has_name ) {
generator . emit < Bytecode : : Op : : SetVariable > ( * name_identifier , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , Bytecode : : Op : : EnvironmentMode : : Lexical ) ;
generator . end_variable_scope ( ) ;
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-11 10:46:46 +02:00
}
2022-02-12 19:54:08 +03:30
static Bytecode : : CodeGenerationErrorOr < void > generate_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode , Bytecode : : Register const & value_reg ) ;
2021-06-13 13:40:48 -07:00
2022-02-12 19:54:08 +03:30
static Bytecode : : CodeGenerationErrorOr < void > generate_object_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode initialization_mode , Bytecode : : Register const & value_reg )
2021-06-13 12:24:55 -07:00
{
2021-06-13 15:30:32 -07:00
Vector < Bytecode : : Register > excluded_property_names ;
auto has_rest = false ;
if ( pattern . entries . size ( ) > 0 )
has_rest = pattern . entries [ pattern . entries . size ( ) - 1 ] . is_rest ;
2021-06-13 12:24:55 -07:00
for ( auto & [ name , alias , initializer , is_rest ] : pattern . entries ) {
2021-06-13 15:30:32 -07:00
if ( is_rest ) {
VERIFY ( name . has < NonnullRefPtr < Identifier > > ( ) ) ;
VERIFY ( alias . has < Empty > ( ) ) ;
VERIFY ( ! initializer ) ;
auto identifier = name . get < NonnullRefPtr < Identifier > > ( ) - > string ( ) ;
2021-10-24 15:34:30 +02:00
auto interned_identifier = generator . intern_identifier ( identifier ) ;
2021-06-13 15:30:32 -07:00
generator . emit_with_extra_register_slots < Bytecode : : Op : : CopyObjectExcludingProperties > ( excluded_property_names . size ( ) , value_reg , excluded_property_names ) ;
2022-02-12 19:54:08 +03:30
generator . emit < Bytecode : : Op : : SetVariable > ( interned_identifier , initialization_mode ) ;
2021-06-13 15:30:32 -07:00
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-13 15:30:32 -07:00
}
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
Bytecode : : StringTableIndex name_index ;
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
if ( name . has < NonnullRefPtr < Identifier > > ( ) ) {
auto identifier = name . get < NonnullRefPtr < Identifier > > ( ) - > string ( ) ;
name_index = generator . intern_string ( identifier ) ;
2021-06-13 15:30:32 -07:00
if ( has_rest ) {
auto excluded_name_reg = generator . allocate_register ( ) ;
excluded_property_names . append ( excluded_name_reg ) ;
generator . emit < Bytecode : : Op : : NewString > ( name_index ) ;
generator . emit < Bytecode : : Op : : Store > ( excluded_name_reg ) ;
}
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : Load > ( value_reg ) ;
2021-10-24 15:34:30 +02:00
generator . emit < Bytecode : : Op : : GetById > ( generator . intern_identifier ( identifier ) ) ;
2021-06-13 13:40:48 -07:00
} else {
auto expression = name . get < NonnullRefPtr < Expression > > ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( expression - > generate_bytecode ( generator ) ) ;
2021-06-13 15:30:32 -07:00
if ( has_rest ) {
auto excluded_name_reg = generator . allocate_register ( ) ;
excluded_property_names . append ( excluded_name_reg ) ;
generator . emit < Bytecode : : Op : : Store > ( excluded_name_reg ) ;
}
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : GetByValue > ( value_reg ) ;
}
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
if ( initializer ) {
auto & if_undefined_block = generator . make_block ( ) ;
auto & if_not_undefined_block = generator . make_block ( ) ;
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : JumpUndefined > ( ) . set_targets (
Bytecode : : Label { if_undefined_block } ,
Bytecode : : Label { if_not_undefined_block } ) ;
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
generator . switch_to_basic_block ( if_undefined_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( initializer - > generate_bytecode ( generator ) ) ;
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { if_not_undefined_block } ,
{ } ) ;
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
generator . switch_to_basic_block ( if_not_undefined_block ) ;
}
2021-06-13 12:24:55 -07:00
2021-06-13 13:40:48 -07:00
if ( alias . has < NonnullRefPtr < BindingPattern > > ( ) ) {
auto & binding_pattern = * alias . get < NonnullRefPtr < BindingPattern > > ( ) ;
auto nested_value_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( nested_value_reg ) ;
2022-02-12 19:54:08 +03:30
TRY ( generate_binding_pattern_bytecode ( generator , binding_pattern , initialization_mode , nested_value_reg ) ) ;
2021-06-13 13:40:48 -07:00
} else if ( alias . has < Empty > ( ) ) {
if ( name . has < NonnullRefPtr < Expression > > ( ) ) {
// This needs some sort of SetVariableByValue opcode, as it's a runtime binding
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
name . get < NonnullRefPtr < Expression > > ( ) . ptr ( ) ,
" Unimplemented name/alias pair: Empty/Expression " sv ,
} ;
2021-06-13 12:24:55 -07:00
}
2021-06-13 13:40:48 -07:00
2022-03-15 01:49:13 +00:00
auto & identifier = name . get < NonnullRefPtr < Identifier > > ( ) - > string ( ) ;
2022-02-12 19:54:08 +03:30
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( identifier ) , initialization_mode ) ;
2021-06-13 12:24:55 -07:00
} else {
2021-06-13 13:40:48 -07:00
auto & identifier = alias . get < NonnullRefPtr < Identifier > > ( ) - > string ( ) ;
2022-02-12 19:54:08 +03:30
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( identifier ) , initialization_mode ) ;
2021-06-13 13:40:48 -07:00
}
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-13 13:40:48 -07:00
}
2022-02-12 19:54:08 +03:30
static Bytecode : : CodeGenerationErrorOr < void > generate_array_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode initialization_mode , Bytecode : : Register const & value_reg )
2021-06-13 13:40:48 -07:00
{
/*
* Consider the following destructuring assignment :
*
* let [ a , b , c , d , e ] = o ;
*
* It would be fairly trivial to just loop through this iterator , getting the value
* at each step and assigning them to the binding sequentially . However , this is not
* correct : once an iterator is exhausted , it must not be called again . This complicates
* the bytecode . In order to accomplish this , we do the following :
*
* - Reserve a special boolean register which holds ' true ' if the iterator is exhausted ,
* and false otherwise
* - When we are retrieving the value which should be bound , we first check this register .
* If it is ' true ' , we load undefined into the accumulator . Otherwise , we grab the next
* value from the iterator and store it into the accumulator .
*
* Note that the is_exhausted register does not need to be loaded with false because the
* first IteratorNext bytecode is _not_ proceeded by an exhausted check , as it is
* unnecessary .
*/
auto is_iterator_exhausted_register = generator . allocate_register ( ) ;
auto iterator_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Load > ( value_reg ) ;
generator . emit < Bytecode : : Op : : GetIterator > ( ) ;
generator . emit < Bytecode : : Op : : Store > ( iterator_reg ) ;
bool first = true ;
auto temp_iterator_result_reg = generator . allocate_register ( ) ;
2021-06-13 14:06:26 -07:00
auto assign_accumulator_to_alias = [ & ] ( auto & alias ) {
2022-02-12 19:54:08 +03:30
return alias . visit (
[ & ] ( Empty ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-06-13 14:06:26 -07:00
// This element is an elision
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-13 14:06:26 -07:00
} ,
2022-02-12 19:54:08 +03:30
[ & ] ( NonnullRefPtr < Identifier > const & identifier ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-10-24 15:34:30 +02:00
auto interned_index = generator . intern_identifier ( identifier - > string ( ) ) ;
2022-02-12 19:54:08 +03:30
generator . emit < Bytecode : : Op : : SetVariable > ( interned_index , initialization_mode ) ;
return { } ;
2021-06-13 14:06:26 -07:00
} ,
2022-02-12 19:54:08 +03:30
[ & ] ( NonnullRefPtr < BindingPattern > const & pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-06-13 14:06:26 -07:00
// Store the accumulator value in a permanent register
auto target_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( target_reg ) ;
2022-02-12 19:54:08 +03:30
return generate_binding_pattern_bytecode ( generator , pattern , initialization_mode , target_reg ) ;
2021-09-18 01:11:32 +02:00
} ,
2022-02-12 19:54:08 +03:30
[ & ] ( NonnullRefPtr < MemberExpression > const & expr ) - > Bytecode : : CodeGenerationErrorOr < void > {
2022-03-31 03:09:08 +04:30
return generator . emit_store_to_reference ( * expr ) ;
2021-06-13 14:06:26 -07:00
} ) ;
} ;
2021-06-13 13:40:48 -07:00
for ( auto & [ name , alias , initializer , is_rest ] : pattern . entries ) {
VERIFY ( name . has < Empty > ( ) ) ;
2021-06-13 14:06:26 -07:00
if ( is_rest ) {
if ( first ) {
// The iterator has not been called, and is thus known to be not exhausted
generator . emit < Bytecode : : Op : : Load > ( iterator_reg ) ;
generator . emit < Bytecode : : Op : : IteratorToArray > ( ) ;
} else {
auto & if_exhausted_block = generator . make_block ( ) ;
auto & if_not_exhausted_block = generator . make_block ( ) ;
auto & continuation_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Load > ( is_iterator_exhausted_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { if_exhausted_block } ,
Bytecode : : Label { if_not_exhausted_block } ) ;
generator . switch_to_basic_block ( if_exhausted_block ) ;
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { continuation_block } ,
{ } ) ;
generator . switch_to_basic_block ( if_not_exhausted_block ) ;
generator . emit < Bytecode : : Op : : Load > ( iterator_reg ) ;
generator . emit < Bytecode : : Op : : IteratorToArray > ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { continuation_block } ,
{ } ) ;
generator . switch_to_basic_block ( continuation_block ) ;
}
2022-02-12 19:54:08 +03:30
return assign_accumulator_to_alias ( alias ) ;
2021-06-13 14:06:26 -07:00
}
2021-06-13 13:40:48 -07:00
// In the first iteration of the loop, a few things are true which can save
// us some bytecode:
// - the iterator result is still in the accumulator, so we can avoid a load
// - the iterator is not yet exhausted, which can save us a jump and some
// creation
auto & iterator_is_exhausted_block = generator . make_block ( ) ;
if ( ! first ) {
auto & iterator_is_not_exhausted_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Load > ( is_iterator_exhausted_register ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { iterator_is_exhausted_block } ,
Bytecode : : Label { iterator_is_not_exhausted_block } ) ;
generator . switch_to_basic_block ( iterator_is_not_exhausted_block ) ;
generator . emit < Bytecode : : Op : : Load > ( iterator_reg ) ;
2021-06-13 12:24:55 -07:00
}
2021-06-13 13:40:48 -07:00
generator . emit < Bytecode : : Op : : IteratorNext > ( ) ;
generator . emit < Bytecode : : Op : : Store > ( temp_iterator_result_reg ) ;
generator . emit < Bytecode : : Op : : IteratorResultDone > ( ) ;
generator . emit < Bytecode : : Op : : Store > ( is_iterator_exhausted_register ) ;
// We still have to check for exhaustion here. If the iterator is exhausted,
// we need to bail before trying to get the value
auto & no_bail_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { iterator_is_exhausted_block } ,
Bytecode : : Label { no_bail_block } ) ;
generator . switch_to_basic_block ( no_bail_block ) ;
// Get the next value in the iterator
generator . emit < Bytecode : : Op : : Load > ( temp_iterator_result_reg ) ;
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
auto & create_binding_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { create_binding_block } ,
{ } ) ;
// The iterator is exhausted, so we just load undefined and continue binding
generator . switch_to_basic_block ( iterator_is_exhausted_block ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { create_binding_block } ,
{ } ) ;
// Create the actual binding. The value which this entry must bind is now in the
// accumulator. We can proceed, processing the alias as a nested destructuring
// pattern if necessary.
generator . switch_to_basic_block ( create_binding_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( assign_accumulator_to_alias ( alias ) ) ;
2021-06-13 13:40:48 -07:00
first = false ;
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-13 13:40:48 -07:00
}
2022-02-12 19:54:08 +03:30
static Bytecode : : CodeGenerationErrorOr < void > generate_binding_pattern_bytecode ( Bytecode : : Generator & generator , BindingPattern const & pattern , Bytecode : : Op : : SetVariable : : InitializationMode initialization_mode , Bytecode : : Register const & value_reg )
2021-06-13 13:40:48 -07:00
{
2022-02-12 19:54:08 +03:30
if ( pattern . kind = = BindingPattern : : Kind : : Object )
return generate_object_binding_pattern_bytecode ( generator , pattern , initialization_mode , value_reg ) ;
return generate_array_binding_pattern_bytecode ( generator , pattern , initialization_mode , value_reg ) ;
}
2021-06-13 12:24:55 -07:00
2022-03-18 20:18:19 +03:30
static Bytecode : : CodeGenerationErrorOr < void > assign_accumulator_to_variable_declarator ( Bytecode : : Generator & generator , VariableDeclarator const & declarator , VariableDeclaration const & declaration )
{
auto initialization_mode = declaration . is_lexical_declaration ( ) ? Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize : Bytecode : : Op : : SetVariable : : InitializationMode : : Set ;
auto environment_mode = declaration . is_lexical_declaration ( ) ? Bytecode : : Op : : EnvironmentMode : : Lexical : Bytecode : : Op : : EnvironmentMode : : Var ;
return declarator . target ( ) . visit (
[ & ] ( NonnullRefPtr < Identifier > const & id ) - > Bytecode : : CodeGenerationErrorOr < void > {
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( id - > string ( ) ) , initialization_mode , environment_mode ) ;
return { } ;
} ,
[ & ] ( NonnullRefPtr < BindingPattern > const & pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
auto value_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( value_register ) ;
return generate_binding_pattern_bytecode ( generator , pattern , initialization_mode , value_register ) ;
} ) ;
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > VariableDeclaration : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-10 00:29:17 +02:00
{
2021-06-10 22:12:21 +02:00
for ( auto & declarator : m_declarations ) {
if ( declarator . init ( ) )
2022-02-12 19:54:08 +03:30
TRY ( declarator . init ( ) - > generate_bytecode ( generator ) ) ;
2021-06-10 22:12:21 +02:00
else
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2022-03-18 20:18:19 +03:30
TRY ( assign_accumulator_to_variable_declarator ( generator , declarator , * this ) ) ;
2021-06-10 22:12:21 +02:00
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-10 00:29:17 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > CallExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-05 15:15:30 +02:00
{
2021-06-07 20:58:36 -07:00
auto callee_reg = generator . allocate_register ( ) ;
2021-06-05 15:15:30 +02:00
auto this_reg = generator . allocate_register ( ) ;
2021-06-07 20:58:36 -07:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Store > ( this_reg ) ;
2021-06-05 15:15:30 +02:00
2021-06-11 01:36:10 +04:30
if ( is < NewExpression > ( this ) ) {
2022-02-12 19:54:08 +03:30
TRY ( m_callee - > generate_bytecode ( generator ) ) ;
2021-06-11 01:36:10 +04:30
generator . emit < Bytecode : : Op : : Store > ( callee_reg ) ;
} else if ( is < SuperExpression > ( * m_callee ) ) {
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented callee kind: SuperExpression " sv ,
} ;
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 ) ;
2021-06-11 01:36:10 +04:30
if ( is < SuperExpression > ( member_expression . object ( ) ) ) {
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented callee kind: MemberExpression on SuperExpression " sv ,
} ;
}
TRY ( member_expression . object ( ) . generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : Store > ( this_reg ) ;
if ( member_expression . is_computed ( ) ) {
TRY ( member_expression . property ( ) . generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : GetByValue > ( this_reg ) ;
2021-06-11 01:36:10 +04:30
} else {
2022-02-12 19:54:08 +03:30
auto identifier_table_ref = generator . intern_identifier ( verify_cast < Identifier > ( member_expression . property ( ) ) . string ( ) ) ;
generator . emit < Bytecode : : Op : : GetById > ( identifier_table_ref ) ;
2021-06-11 01:36:10 +04:30
}
2022-02-12 19:54:08 +03:30
generator . emit < Bytecode : : Op : : Store > ( callee_reg ) ;
2021-06-11 01:36:10 +04:30
} else {
// FIXME: this = global object in sloppy mode.
2022-02-12 19:54:08 +03:30
TRY ( m_callee - > generate_bytecode ( generator ) ) ;
2021-06-11 01:36:10 +04:30
generator . emit < Bytecode : : Op : : Store > ( callee_reg ) ;
}
2021-06-05 15:15:30 +02:00
Vector < Bytecode : : Register > argument_registers ;
2021-06-07 20:58:36 -07:00
for ( auto & arg : m_arguments ) {
2022-02-12 19:54:08 +03:30
TRY ( arg . value - > generate_bytecode ( generator ) ) ;
2021-06-07 20:58:36 -07:00
auto arg_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( arg_reg ) ;
argument_registers . append ( arg_reg ) ;
}
2021-06-10 23:01:49 +02:00
Bytecode : : Op : : Call : : CallType call_type ;
if ( is < NewExpression > ( * this ) ) {
call_type = Bytecode : : Op : : Call : : CallType : : Construct ;
} else {
call_type = Bytecode : : Op : : Call : : CallType : : Call ;
}
generator . emit_with_extra_register_slots < Bytecode : : Op : : Call > ( argument_registers . size ( ) , call_type , callee_reg , this_reg , argument_registers ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-05 15:15:30 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ReturnStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-05 15:53:36 +02:00
{
2021-06-08 16:29:21 -07:00
if ( m_argument )
2022-02-12 19:54:08 +03:30
TRY ( m_argument - > generate_bytecode ( generator ) ) ;
2022-06-11 23:13:02 +01:00
else
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2021-06-11 01:38:30 +04:30
2022-03-13 11:51:02 +03:30
if ( generator . is_in_generator_or_async_function ( ) ) {
generator . perform_needed_unwinds < Bytecode : : Op : : Yield > ( ) ;
2021-06-11 01:38:30 +04:30
generator . emit < Bytecode : : Op : : Yield > ( nullptr ) ;
2022-03-13 11:51:02 +03:30
} else {
generator . perform_needed_unwinds < Bytecode : : Op : : Return > ( ) ;
2021-06-11 01:38:30 +04:30
generator . emit < Bytecode : : Op : : Return > ( ) ;
2022-03-13 11:51:02 +03:30
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-11 01:38:30 +04:30
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > YieldExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-11 01:38:30 +04:30
{
VERIFY ( generator . is_in_generator_function ( ) ) ;
2022-02-12 19:54:08 +03:30
if ( m_is_yield_from ) {
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented form: `yield*` " sv ,
} ;
}
2021-06-14 15:46:41 +04:30
2021-06-11 01:38:30 +04:30
if ( m_argument )
2022-02-12 19:54:08 +03:30
TRY ( m_argument - > generate_bytecode ( generator ) ) ;
2021-06-11 01:38:30 +04:30
auto & continuation_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( Bytecode : : Label { continuation_block } ) ;
generator . switch_to_basic_block ( continuation_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-05 15:53:36 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > IfStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-06 13:26:50 +02:00
{
2021-06-09 06:49:58 +04:30
// test
// jump if_true (true) true (false) false
// true
// jump always (true) end
// false
// jump always (true) end
// end
auto & true_block = generator . make_block ( ) ;
auto & false_block = generator . make_block ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_predicate - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { true_block } ,
Bytecode : : Label { false_block } ) ;
Bytecode : : Op : : Jump * true_block_jump { nullptr } ;
2021-06-06 13:26:50 +02:00
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( true_block ) ;
2021-06-20 12:38:59 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_consequent - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
if ( ! generator . is_current_block_terminated ( ) )
true_block_jump = & generator . emit < Bytecode : : Op : : Jump > ( ) ;
generator . switch_to_basic_block ( false_block ) ;
2021-06-20 12:38:59 +02:00
auto & end_block = generator . make_block ( ) ;
2021-06-09 06:49:58 +04:30
2021-06-20 12:38:59 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
if ( m_alternate )
2022-02-12 19:54:08 +03:30
TRY ( m_alternate - > generate_bytecode ( generator ) ) ;
2021-06-20 12:38:59 +02:00
if ( ! generator . is_current_block_terminated ( ) )
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { end_block } , { } ) ;
2021-06-09 06:49:58 +04:30
2021-06-20 12:38:59 +02:00
if ( true_block_jump )
true_block_jump - > set_targets ( Bytecode : : Label { end_block } , { } ) ;
2021-06-09 06:49:58 +04:30
2021-06-20 12:38:59 +02:00
generator . switch_to_basic_block ( end_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-06 13:26:50 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ContinueStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-06 13:33:02 +02:00
{
2022-06-11 23:09:37 +01:00
if ( m_target_label . is_null ( ) ) {
generator . perform_needed_unwinds < Bytecode : : Op : : Jump > ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
generator . nearest_continuable_scope ( ) ,
{ } ) ;
return { } ;
}
auto target_to_jump_to = generator . perform_needed_unwinds_for_labelled_continue_and_return_target_block ( m_target_label ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
2022-06-11 23:09:37 +01:00
target_to_jump_to ,
2021-06-09 06:49:58 +04:30
{ } ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-06 13:33:02 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > DebuggerStatement : : generate_bytecode ( Bytecode : : Generator & ) const
2021-06-07 20:05:50 +01:00
{
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-07 20:05:50 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ConditionalExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 04:54:34 +01:00
{
2021-06-09 06:49:58 +04:30
// test
// jump if_true (true) true (false) false
// true
// jump always (true) end
// false
// jump always (true) end
// end
auto & true_block = generator . make_block ( ) ;
auto & false_block = generator . make_block ( ) ;
auto & end_block = generator . make_block ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_test - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets (
Bytecode : : Label { true_block } ,
Bytecode : : Label { false_block } ) ;
2021-06-08 04:54:34 +01:00
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( true_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_consequent - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { end_block } ,
{ } ) ;
2021-06-08 04:54:34 +01:00
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( false_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_alternate - > generate_bytecode ( generator ) ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
Bytecode : : Label { end_block } ,
{ } ) ;
2021-06-08 04:54:34 +01:00
2021-06-09 06:49:58 +04:30
generator . switch_to_basic_block ( end_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 04:54:34 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > SequenceExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 10:13:37 +01:00
{
for ( auto & expression : m_expressions )
2022-02-12 19:54:08 +03:30
TRY ( expression . generate_bytecode ( generator ) ) ;
return { } ;
2021-06-08 10:13:37 +01:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > TemplateLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-08 19:14:01 +02:00
{
2021-06-07 20:58:36 -07:00
auto string_reg = generator . allocate_register ( ) ;
2021-06-08 19:14:01 +02:00
2021-06-07 20:58:36 -07:00
for ( size_t i = 0 ; i < m_expressions . size ( ) ; i + + ) {
2022-02-12 19:54:08 +03:30
TRY ( m_expressions [ i ] . generate_bytecode ( generator ) ) ;
2021-06-07 20:58:36 -07:00
if ( i = = 0 ) {
generator . emit < Bytecode : : Op : : Store > ( string_reg ) ;
} else {
generator . emit < Bytecode : : Op : : ConcatString > ( string_reg ) ;
}
2021-06-08 19:14:01 +02:00
}
2021-06-09 21:11:04 +02:00
generator . emit < Bytecode : : Op : : Load > ( string_reg ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-08 19:14:01 +02:00
}
2021-06-09 11:40:38 +02:00
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > TaggedTemplateLiteral : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-09 21:02:24 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( m_tag - > generate_bytecode ( generator ) ) ;
2021-06-09 22:07:18 +02:00
auto tag_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( tag_reg ) ;
2021-06-09 21:02:24 +02:00
Vector < Bytecode : : Register > string_regs ;
auto & expressions = m_template_literal - > expressions ( ) ;
2022-03-14 14:48:42 +00:00
for ( size_t i = 0 ; i < expressions . size ( ) ; + + i ) {
if ( i % 2 ! = 0 )
continue ;
string_regs . append ( generator . allocate_register ( ) ) ;
}
size_t reg_index = 0 ;
2021-06-09 21:02:24 +02:00
for ( size_t i = 0 ; i < expressions . size ( ) ; + + i ) {
if ( i % 2 ! = 0 )
continue ;
2022-02-12 19:54:08 +03:30
TRY ( expressions [ i ] . generate_bytecode ( generator ) ) ;
2022-03-14 14:48:42 +00:00
auto string_reg = string_regs [ reg_index + + ] ;
2021-06-09 21:02:24 +02:00
generator . emit < Bytecode : : Op : : Store > ( string_reg ) ;
}
2022-03-14 14:48:42 +00:00
if ( string_regs . is_empty ( ) ) {
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
} else {
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2u , AK : : Array { string_regs . first ( ) , string_regs . last ( ) } ) ;
}
2021-06-09 21:02:24 +02:00
auto strings_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( strings_reg ) ;
Vector < Bytecode : : Register > argument_regs ;
argument_regs . append ( strings_reg ) ;
for ( size_t i = 0 ; i < expressions . size ( ) ; + + i ) {
if ( i % 2 = = 0 )
continue ;
2022-02-12 19:54:08 +03:30
TRY ( expressions [ i ] . generate_bytecode ( generator ) ) ;
2021-06-09 21:02:24 +02:00
auto string_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( string_reg ) ;
argument_regs . append ( string_reg ) ;
}
Vector < Bytecode : : Register > raw_string_regs ;
2022-03-14 14:48:42 +00:00
for ( [[maybe_unused]] auto & raw_string : m_template_literal - > raw_strings ( ) )
string_regs . append ( generator . allocate_register ( ) ) ;
reg_index = 0 ;
2021-06-09 21:02:24 +02:00
for ( auto & raw_string : m_template_literal - > raw_strings ( ) ) {
2022-02-12 19:54:08 +03:30
TRY ( raw_string . generate_bytecode ( generator ) ) ;
2022-03-14 14:48:42 +00:00
auto raw_string_reg = string_regs [ reg_index + + ] ;
2021-06-09 21:02:24 +02:00
generator . emit < Bytecode : : Op : : Store > ( raw_string_reg ) ;
raw_string_regs . append ( raw_string_reg ) ;
}
2022-03-14 14:48:42 +00:00
if ( raw_string_regs . is_empty ( ) ) {
generator . emit < Bytecode : : Op : : NewArray > ( ) ;
} else {
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( 2u , AK : : Array { raw_string_regs . first ( ) , raw_string_regs . last ( ) } ) ;
}
2021-06-09 21:02:24 +02:00
auto raw_strings_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( raw_strings_reg ) ;
generator . emit < Bytecode : : Op : : Load > ( strings_reg ) ;
2021-10-24 15:34:30 +02:00
generator . emit < Bytecode : : Op : : PutById > ( raw_strings_reg , generator . intern_identifier ( " raw " ) ) ;
2021-06-09 21:02:24 +02:00
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
auto this_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( this_reg ) ;
2021-06-10 23:01:49 +02:00
generator . emit_with_extra_register_slots < Bytecode : : Op : : Call > ( argument_regs . size ( ) , Bytecode : : Op : : Call : : CallType : : Call , tag_reg , this_reg , move ( argument_regs ) ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-09 21:02:24 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > UpdateExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-09 11:40:38 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( generator . emit_load_from_reference ( * m_argument ) ) ;
2021-06-09 11:40:38 +02:00
2021-10-25 15:17:41 +02:00
Optional < Bytecode : : Register > previous_value_for_postfix_reg ;
if ( ! m_prefixed ) {
previous_value_for_postfix_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( * previous_value_for_postfix_reg ) ;
}
2021-06-09 11:40:38 +02:00
2021-10-25 15:17:41 +02:00
if ( m_op = = UpdateOp : : Increment )
generator . emit < Bytecode : : Op : : Increment > ( ) ;
else
generator . emit < Bytecode : : Op : : Decrement > ( ) ;
2021-06-09 11:40:38 +02:00
2022-02-12 19:54:08 +03:30
TRY ( generator . emit_store_to_reference ( * m_argument ) ) ;
2021-06-09 11:40:38 +02:00
2021-10-25 15:17:41 +02:00
if ( ! m_prefixed )
generator . emit < Bytecode : : Op : : Load > ( * previous_value_for_postfix_reg ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-09 11:40:38 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ThrowStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-09 18:18:56 +02:00
{
2022-02-12 19:54:08 +03:30
TRY ( m_argument - > generate_bytecode ( generator ) ) ;
2022-03-14 02:26:39 +00:00
generator . perform_needed_unwinds < Bytecode : : Op : : Throw > ( ) ;
2021-06-09 18:18:56 +02:00
generator . emit < Bytecode : : Op : : Throw > ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-09 18:18:56 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > BreakStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-10 20:28:43 +08:00
{
2022-06-11 23:09:37 +01:00
if ( m_target_label . is_null ( ) ) {
generator . perform_needed_unwinds < Bytecode : : Op : : Jump > ( true ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
generator . nearest_breakable_scope ( ) ,
{ } ) ;
return { } ;
}
auto target_to_jump_to = generator . perform_needed_unwinds_for_labelled_break_and_return_target_block ( m_target_label ) ;
2021-06-10 20:28:43 +08:00
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
2022-06-11 23:09:37 +01:00
target_to_jump_to ,
2021-06-10 20:28:43 +08:00
{ } ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-10 20:28:43 +08:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > TryStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-10 15:04:38 +02:00
{
auto & saved_block = generator . current_block ( ) ;
Optional < Bytecode : : Label > handler_target ;
Optional < Bytecode : : Label > finalizer_target ;
Bytecode : : BasicBlock * next_block { nullptr } ;
if ( m_finalizer ) {
auto & finalizer_block = generator . make_block ( ) ;
generator . switch_to_basic_block ( finalizer_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_finalizer - > generate_bytecode ( generator ) ) ;
2021-06-10 15:04:38 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
next_block = & generator . make_block ( ) ;
auto next_target = Bytecode : : Label { * next_block } ;
generator . emit < Bytecode : : Op : : ContinuePendingUnwind > ( next_target ) ;
}
finalizer_target = Bytecode : : Label { finalizer_block } ;
}
if ( m_handler ) {
auto & handler_block = generator . make_block ( ) ;
generator . switch_to_basic_block ( handler_block ) ;
2022-03-14 02:38:13 +00:00
generator . begin_variable_scope ( Bytecode : : Generator : : BindingMode : : Lexical , Bytecode : : Generator : : SurroundingScopeKind : : Block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_handler - > parameter ( ) . visit (
[ & ] ( FlyString const & parameter ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-10-24 22:46:54 +02:00
if ( ! parameter . is_empty ( ) ) {
2022-03-14 02:38:13 +00:00
auto parameter_identifier = generator . intern_identifier ( parameter ) ;
generator . register_binding ( parameter_identifier ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( parameter_identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( parameter_identifier , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
2021-07-11 15:15:38 +04:30
}
2022-02-12 19:54:08 +03:30
return { } ;
2021-07-11 15:15:38 +04:30
} ,
2022-02-12 19:54:08 +03:30
[ & ] ( NonnullRefPtr < BindingPattern > const & ) - > Bytecode : : CodeGenerationErrorOr < void > {
2022-01-06 07:07:15 -07:00
// FIXME: Implement this path when the above DeclarativeEnvironment issue is dealt with.
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented catch argument: BindingPattern " sv ,
} ;
} ) ) ;
2021-07-11 15:15:38 +04:30
2022-02-12 19:54:08 +03:30
TRY ( m_handler - > body ( ) . generate_bytecode ( generator ) ) ;
2021-06-10 15:04:38 +02:00
handler_target = Bytecode : : Label { handler_block } ;
2022-03-14 02:38:13 +00:00
generator . end_variable_scope ( ) ;
2021-06-10 15:04:38 +02:00
if ( ! generator . is_current_block_terminated ( ) ) {
if ( m_finalizer ) {
generator . emit < Bytecode : : Op : : LeaveUnwindContext > ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( finalizer_target ) ;
} else {
VERIFY ( ! next_block ) ;
next_block = & generator . make_block ( ) ;
auto next_target = Bytecode : : Label { * next_block } ;
generator . emit < Bytecode : : Op : : Jump > ( next_target ) ;
}
}
}
2021-06-13 20:39:40 +04:30
auto & target_block = generator . make_block ( ) ;
2021-06-10 15:04:38 +02:00
generator . switch_to_basic_block ( saved_block ) ;
2021-06-13 20:39:40 +04:30
generator . emit < Bytecode : : Op : : EnterUnwindContext > ( Bytecode : : Label { target_block } , handler_target , finalizer_target ) ;
2022-03-13 11:51:02 +03:30
generator . start_boundary ( Bytecode : : Generator : : BlockBoundaryType : : Unwind ) ;
2021-06-13 20:39:40 +04:30
generator . switch_to_basic_block ( target_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_block - > generate_bytecode ( generator ) ) ;
2021-11-10 22:22:26 +03:30
if ( ! generator . is_current_block_terminated ( ) ) {
if ( m_finalizer ) {
generator . emit < Bytecode : : Op : : Jump > ( finalizer_target ) ;
} else {
auto & block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : FinishUnwind > ( Bytecode : : Label { block } ) ;
next_block = & block ;
}
}
2022-03-13 11:51:02 +03:30
generator . end_boundary ( Bytecode : : Generator : : BlockBoundaryType : : Unwind ) ;
2021-06-10 15:04:38 +02:00
generator . switch_to_basic_block ( next_block ? * next_block : saved_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-10 15:04:38 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > SwitchStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
Bytecode : : CodeGenerationErrorOr < void > SwitchStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < FlyString > const & label_set ) const
2021-06-11 00:36:16 +02:00
{
auto discriminant_reg = generator . allocate_register ( ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_discriminant - > generate_bytecode ( generator ) ) ;
2021-06-11 00:36:16 +02:00
generator . emit < Bytecode : : Op : : Store > ( discriminant_reg ) ;
Vector < Bytecode : : BasicBlock & > case_blocks ;
Bytecode : : BasicBlock * default_block { nullptr } ;
Bytecode : : BasicBlock * next_test_block = & generator . make_block ( ) ;
2022-04-03 02:13:51 +04:30
auto has_lexical_block = has_lexical_declarations ( ) ;
// Note: This call ends up calling begin_variable_scope() if has_lexical_block is true, so we need to clean up after it at the end.
TRY ( ScopeNode : : generate_bytecode ( generator ) ) ;
2021-06-11 00:36:16 +02:00
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { * next_test_block } , { } ) ;
2022-04-03 02:13:51 +04:30
2021-06-11 00:36:16 +02:00
for ( auto & switch_case : m_cases ) {
auto & case_block = generator . make_block ( ) ;
if ( switch_case . test ( ) ) {
generator . switch_to_basic_block ( * next_test_block ) ;
2022-02-12 19:54:08 +03:30
TRY ( switch_case . test ( ) - > generate_bytecode ( generator ) ) ;
2021-09-24 00:06:10 +02:00
generator . emit < Bytecode : : Op : : StrictlyEquals > ( discriminant_reg ) ;
2021-06-11 00:36:16 +02:00
next_test_block = & generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets ( Bytecode : : Label { case_block } , Bytecode : : Label { * next_test_block } ) ;
} else {
default_block = & case_block ;
}
case_blocks . append ( case_block ) ;
}
generator . switch_to_basic_block ( * next_test_block ) ;
auto & end_block = generator . make_block ( ) ;
if ( default_block ! = nullptr ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { * default_block } , { } ) ;
} else {
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { end_block } , { } ) ;
}
auto current_block = case_blocks . begin ( ) ;
2022-06-11 23:09:37 +01:00
generator . begin_breakable_scope ( Bytecode : : Label { end_block } , label_set ) ;
2021-06-11 00:36:16 +02:00
for ( auto & switch_case : m_cases ) {
generator . switch_to_basic_block ( * current_block ) ;
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
2021-09-22 12:44:56 +02:00
for ( auto & statement : switch_case . children ( ) ) {
2022-02-12 19:54:08 +03:30
TRY ( statement . generate_bytecode ( generator ) ) ;
2022-03-15 01:43:44 +00:00
if ( generator . is_current_block_terminated ( ) )
break ;
2021-06-11 00:36:16 +02:00
}
if ( ! generator . is_current_block_terminated ( ) ) {
auto next_block = current_block ;
next_block + + ;
if ( next_block . is_end ( ) ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { end_block } , { } ) ;
} else {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { * next_block } , { } ) ;
}
}
current_block + + ;
}
generator . end_breakable_scope ( ) ;
2022-04-03 02:13:51 +04:30
if ( has_lexical_block )
generator . end_variable_scope ( ) ;
2021-06-11 00:36:16 +02:00
generator . switch_to_basic_block ( end_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-11 00:36:16 +02:00
}
2022-02-12 19:55:40 +03:30
Bytecode : : CodeGenerationErrorOr < void > ClassDeclaration : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-06-30 15:42:13 -03:00
{
2022-02-12 19:55:40 +03:30
TRY ( m_class_expression - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( m_class_expression . ptr ( ) - > name ( ) ) , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
return { } ;
}
Bytecode : : CodeGenerationErrorOr < void > ClassExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
generator . emit < Bytecode : : Op : : NewClass > ( * this ) ;
return { } ;
2021-06-30 15:42:13 -03:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > ThisExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-10-24 14:43:00 +02:00
{
generator . emit < Bytecode : : Op : : ResolveThisBinding > ( ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-10-24 14:43:00 +02:00
}
2022-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > AwaitExpression : : generate_bytecode ( Bytecode : : Generator & generator ) const
2021-11-11 00:46:07 +03:30
{
VERIFY ( generator . is_in_async_function ( ) ) ;
// Transform `await expr` to `yield expr`
2022-02-12 19:54:08 +03:30
TRY ( m_argument - > generate_bytecode ( generator ) ) ;
2021-11-11 00:46:07 +03:30
auto & continuation_block = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : Yield > ( Bytecode : : Label { continuation_block } ) ;
generator . switch_to_basic_block ( continuation_block ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-11-11 00:46:07 +03:30
}
2022-03-13 16:01:18 +03:30
Bytecode : : CodeGenerationErrorOr < void > WithStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
TRY ( m_object - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : EnterObjectEnvironment > ( ) ;
2022-03-14 02:35:45 +00:00
// EnterObjectEnvironment sets the running execution context's lexical_environment to a new Object Environment.
generator . start_boundary ( Bytecode : : Generator : : BlockBoundaryType : : LeaveLexicalEnvironment ) ;
2022-03-13 16:01:18 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
2022-03-14 02:35:45 +00:00
generator . end_boundary ( Bytecode : : Generator : : BlockBoundaryType : : LeaveLexicalEnvironment ) ;
if ( ! generator . is_current_block_terminated ( ) )
generator . emit < Bytecode : : Op : : LeaveEnvironment > ( Bytecode : : Op : : EnvironmentMode : : Lexical ) ;
2022-03-13 16:01:18 +03:30
return { } ;
}
2022-03-18 20:18:19 +03:30
enum class LHSKind {
Assignment ,
VarBinding ,
LexicalBinding ,
} ;
enum class IterationKind {
Enumerate ,
Iterate ,
AsyncIterate ,
} ;
// 14.7.5.6 ForIn/OfHeadEvaluation ( uninitializedBoundNames, expr, iterationKind ), https://tc39.es/ecma262/#sec-runtime-semantics-forinofheadevaluation
struct ForInOfHeadEvaluationResult {
bool is_destructuring { false } ;
LHSKind lhs_kind { LHSKind : : Assignment } ;
} ;
static Bytecode : : CodeGenerationErrorOr < ForInOfHeadEvaluationResult > for_in_of_head_evaluation ( Bytecode : : Generator & generator , IterationKind iteration_kind , Variant < NonnullRefPtr < ASTNode > , NonnullRefPtr < BindingPattern > > const & lhs , NonnullRefPtr < ASTNode > const & rhs )
{
ForInOfHeadEvaluationResult result { } ;
if ( auto * ast_ptr = lhs . get_pointer < NonnullRefPtr < ASTNode > > ( ) ; ast_ptr & & is < VariableDeclaration > ( * * ast_ptr ) ) {
// 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 ) ;
result . is_destructuring = variable_declaration . declarations ( ) . first ( ) . target ( ) . has < NonnullRefPtr < BindingPattern > > ( ) ;
result . lhs_kind = variable_declaration . is_lexical_declaration ( ) ? LHSKind : : LexicalBinding : LHSKind : : VarBinding ;
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
// NOTE: 'uninitializedBoundNames' refers to the lexical bindings (i.e. Const/Let) present in the second and last form.
// 2. If uninitializedBoundNames is not an empty List, then
bool entered_lexical_scope = false ;
if ( variable_declaration . declaration_kind ( ) ! = DeclarationKind : : Var ) {
entered_lexical_scope = true ;
// a. Assert: uninitializedBoundNames has no duplicate entries.
// b. Let newEnv be NewDeclarativeEnvironment(oldEnv).
generator . begin_variable_scope ( ) ;
// c. For each String name of uninitializedBoundNames, do
variable_declaration . for_each_bound_name ( [ & ] ( auto const & name ) {
// i. Perform ! newEnv.CreateMutableBinding(name, false).
auto identifier = generator . intern_identifier ( name ) ;
generator . register_binding ( identifier ) ;
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
} ) ;
// d. Set the running execution context's LexicalEnvironment to newEnv.
// NOTE: Done by CreateEnvironment.
}
// 3. Let exprRef be the result of evaluating expr.
TRY ( rhs - > generate_bytecode ( generator ) ) ;
// 4. Set the running execution context's LexicalEnvironment to oldEnv.
if ( entered_lexical_scope )
generator . end_variable_scope ( ) ;
// 5. Let exprValue be ? GetValue(exprRef).
// NOTE: No need to store this anywhere.
// 6. If iterationKind is enumerate, then
if ( iteration_kind = = IterationKind : : Enumerate ) {
// a. If exprValue is undefined or null, then
auto & nullish_block = generator . make_block ( ) ;
auto & continuation_block = generator . make_block ( ) ;
auto & jump = generator . emit < Bytecode : : Op : : JumpNullish > ( ) ;
jump . set_targets ( Bytecode : : Label { nullish_block } , Bytecode : : Label { continuation_block } ) ;
// i. Return Completion Record { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }.
generator . switch_to_basic_block ( nullish_block ) ;
generator . perform_needed_unwinds < Bytecode : : Op : : Jump > ( true ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( generator . nearest_breakable_scope ( ) , { } ) ;
generator . switch_to_basic_block ( continuation_block ) ;
// b. Let obj be ! ToObject(exprValue).
// NOTE: GetObjectPropertyIterator does this.
// c. Let iterator be EnumerateObjectProperties(obj).
// d. Let nextMethod be ! GetV(iterator, "next").
// e. Return the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
generator . emit < Bytecode : : Op : : GetObjectPropertyIterator > ( ) ;
}
// 7. Else,
else {
// a. Assert: iterationKind is iterate or async-iterate.
// b. If iterationKind is async-iterate, let iteratorHint be async.
if ( iteration_kind = = IterationKind : : AsyncIterate ) {
return Bytecode : : CodeGenerationError {
rhs . ptr ( ) ,
" Unimplemented iteration mode: AsyncIterate " sv ,
} ;
}
// c. Else, let iteratorHint be sync.
// d. Return ? GetIterator(exprValue, iteratorHint).
generator . emit < Bytecode : : Op : : GetIterator > ( ) ;
}
} else {
// Runtime Semantics: ForInOfLoopEvaluation, for any of:
// ForInOfStatement : for ( LeftHandSideExpression in Expression ) Statement
// ForInOfStatement : for ( LeftHandSideExpression of AssignmentExpression ) Statement
// Skip everything except steps 3, 5 and 7 (see above true branch for listing).
result . lhs_kind = LHSKind : : Assignment ;
// 3. Let exprRef be the result of evaluating expr.
TRY ( rhs - > generate_bytecode ( generator ) ) ;
// 5. Let exprValue be ? GetValue(exprRef).
// NOTE: No need to store this anywhere.
// a. Assert: iterationKind is iterate or async-iterate.
// b. If iterationKind is async-iterate, let iteratorHint be async.
if ( iteration_kind = = IterationKind : : AsyncIterate ) {
return Bytecode : : CodeGenerationError {
rhs . ptr ( ) ,
" Unimplemented iteration mode: AsyncIterate " sv ,
} ;
}
// c. Else, let iteratorHint be sync.
// d. Return ? GetIterator(exprValue, iteratorHint).
generator . emit < Bytecode : : Op : : GetIterator > ( ) ;
}
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
2022-06-11 23:09:37 +01:00
static Bytecode : : CodeGenerationErrorOr < void > for_in_of_body_evaluation ( Bytecode : : Generator & generator , ASTNode const & node , Variant < NonnullRefPtr < ASTNode > , NonnullRefPtr < BindingPattern > > const & lhs , ASTNode const & body , ForInOfHeadEvaluationResult const & head_result , Vector < FlyString > const & label_set , Bytecode : : BasicBlock & loop_end , Bytecode : : BasicBlock & loop_update )
2022-03-18 20:18:19 +03:30
{
auto iterator_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( iterator_register ) ;
// FIXME: Implement this
// 1. If iteratorKind is not present, set iteratorKind to sync.
// 2. Let oldEnv be the running execution context's LexicalEnvironment.
bool has_lexical_binding = false ;
// 3. Let V be undefined.
// NOTE: We don't need 'V' as the resulting value will naturally flow through via the accumulator register.
// 4. Let destructuring be IsDestructuring of lhs.
auto destructuring = head_result . is_destructuring ;
// 5. If destructuring is true and if lhsKind is assignment, then
if ( destructuring ) {
// a. Assert: lhs is a LeftHandSideExpression.
// b. Let assignmentPattern be the AssignmentPattern that is covered by lhs.
// FIXME: Implement this.
return Bytecode : : CodeGenerationError {
& node ,
" Unimplemented: destructuring in for-in/of " sv ,
} ;
}
// 6. Repeat,
generator . emit < Bytecode : : Op : : Jump > ( Bytecode : : Label { loop_update } ) ;
generator . switch_to_basic_block ( loop_update ) ;
2022-06-11 23:09:37 +01:00
generator . begin_continuable_scope ( Bytecode : : Label { loop_update } , label_set ) ;
2022-03-18 20:18:19 +03:30
// a. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
generator . emit < Bytecode : : Op : : Load > ( iterator_register ) ;
generator . emit < Bytecode : : Op : : IteratorNext > ( ) ;
// FIXME: Implement this:
// b. If iteratorKind is async, set nextResult to ? Await(nextResult).
// c. If Type(nextResult) is not Object, throw a TypeError exception.
// NOTE: IteratorComplete already does this.
// d. Let done be ? IteratorComplete(nextResult).
auto iterator_result_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( iterator_result_register ) ;
generator . emit < Bytecode : : Op : : IteratorResultDone > ( ) ;
// e. If done is true, return V.
auto & loop_continue = generator . make_block ( ) ;
generator . emit < Bytecode : : Op : : JumpConditional > ( ) . set_targets ( Bytecode : : Label { loop_end } , Bytecode : : Label { loop_continue } ) ;
generator . switch_to_basic_block ( loop_continue ) ;
// f. Let nextValue be ? IteratorValue(nextResult).
generator . emit < Bytecode : : Op : : Load > ( iterator_result_register ) ;
generator . emit < Bytecode : : Op : : IteratorResultValue > ( ) ;
// g. If lhsKind is either assignment or varBinding, then
if ( head_result . lhs_kind ! = LHSKind : : LexicalBinding ) {
// i. If destructuring is false, then
if ( ! destructuring ) {
// 1. Let lhsRef be the result of evaluating lhs. (It may be evaluated repeatedly.)
// NOTE: We're skipping all the completion stuff that the spec does, as the unwinding mechanism will take case of doing that.
if ( head_result . lhs_kind = = LHSKind : : VarBinding ) {
auto & declaration = static_cast < VariableDeclaration const & > ( * lhs . get < NonnullRefPtr < ASTNode > > ( ) ) ;
VERIFY ( declaration . declarations ( ) . size ( ) = = 1 ) ;
TRY ( assign_accumulator_to_variable_declarator ( generator , declaration . declarations ( ) . first ( ) , declaration ) ) ;
} else {
2022-03-31 03:09:36 +04:30
if ( auto ptr = lhs . get_pointer < NonnullRefPtr < ASTNode > > ( ) ) {
TRY ( generator . emit_store_to_reference ( * * ptr ) ) ;
} else {
auto & binding_pattern = lhs . get < NonnullRefPtr < BindingPattern > > ( ) ;
TRY ( generate_binding_pattern_bytecode ( generator , * binding_pattern , Bytecode : : Op : : SetVariable : : InitializationMode : : Set , Bytecode : : Register : : accumulator ( ) ) ) ;
}
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.
generator . begin_variable_scope ( Bytecode : : Generator : : BindingMode : : Lexical ) ;
has_lexical_binding = true ;
// 14.7.5.4 Runtime Semantics: ForDeclarationBindingInstantiation, https://tc39.es/ecma262/#sec-runtime-semantics-fordeclarationbindinginstantiation
// 1. Assert: environment is a declarative Environment Record.
// NOTE: We just made it.
auto & variable_declaration = static_cast < VariableDeclaration const & > ( * lhs . get < NonnullRefPtr < ASTNode > > ( ) ) ;
// 2. For each element name of the BoundNames of ForBinding, do
variable_declaration . for_each_bound_name ( [ & ] ( auto const & name ) {
auto identifier = generator . intern_identifier ( name ) ;
generator . register_binding ( identifier , Bytecode : : Generator : : BindingMode : : Lexical ) ;
// a. If IsConstantDeclaration of LetOrConst is true, then
if ( variable_declaration . is_constant_declaration ( ) ) {
// i. Perform ! environment.CreateImmutableBinding(name, true).
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , true ) ;
}
// b. Else,
else {
// i. Perform ! environment.CreateMutableBinding(name, false).
generator . emit < Bytecode : : Op : : CreateVariable > ( identifier , Bytecode : : Op : : EnvironmentMode : : Lexical , false ) ;
}
} ) ;
// 3. Return unused.
// NOTE: No need to do that as we've inlined this.
// vi. If destructuring is false, then
if ( ! destructuring ) {
// 1. Assert: lhs binds a single name.
// 2. Let lhsName be the sole element of BoundNames of lhs.
auto lhs_name = variable_declaration . declarations ( ) . first ( ) . target ( ) . get < NonnullRefPtr < Identifier > > ( ) - > string ( ) ;
// 3. Let lhsRef be ! ResolveBinding(lhsName).
// NOTE: We're skipping all the completion stuff that the spec does, as the unwinding mechanism will take case of doing that.
auto identifier = generator . intern_identifier ( lhs_name ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( identifier , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , Bytecode : : Op : : EnvironmentMode : : Lexical ) ;
}
}
// i. If destructuring is false, then
if ( ! destructuring ) {
// i. If lhsRef is an abrupt completion, then
// 1. Let status be lhsRef.
// ii. Else if lhsKind is lexicalBinding, then
// 1. Let status be Completion(InitializeReferencedBinding(lhsRef, nextValue)).
// iii. Else,
// 1. Let status be Completion(PutValue(lhsRef, nextValue)).
// NOTE: This is performed above.
}
// j. Else,
else {
// FIXME: Implement destructuring
// i. If lhsKind is assignment, then
// 1. Let status be Completion(DestructuringAssignmentEvaluation of assignmentPattern with argument nextValue).
// 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).
return Bytecode : : CodeGenerationError {
& node ,
" Unimplemented: destructuring in for-in/of " sv ,
} ;
}
// FIXME: Implement iteration closure.
// k. If status is an abrupt completion, then
// i. Set the running execution context's LexicalEnvironment to oldEnv.
// ii. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
// iii. If iterationKind is enumerate, then
// 1. Return ? status.
// iv. Else,
// 1. Assert: iterationKind is iterate.
// 2. Return ? IteratorClose(iteratorRecord, status).
// l. Let result be the result of evaluating stmt.
TRY ( body . generate_bytecode ( generator ) ) ;
// m. Set the running execution context's LexicalEnvironment to oldEnv.
if ( has_lexical_binding )
generator . end_variable_scope ( ) ;
generator . end_continuable_scope ( ) ;
generator . end_breakable_scope ( ) ;
// NOTE: If we're here, then the loop definitely continues.
// n. If LoopContinues(result, labelSet) is false, then
// i. If iterationKind is enumerate, then
// 1. Return ? UpdateEmpty(result, V).
// ii. Else,
// 1. Assert: iterationKind is iterate.
// 2. Set status to Completion(UpdateEmpty(result, V)).
// 3. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
// 4. Return ? IteratorClose(iteratorRecord, status).
// o. If result.[[Value]] is not empty, set V to result.[[Value]].
2022-03-27 18:46:25 +01:00
// The body can contain an unconditional block terminator (e.g. return, throw), so we have to check for that before generating the Jump.
if ( ! generator . is_current_block_terminated ( ) )
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { loop_update } , { } ) ;
2022-03-18 20:18:19 +03:30
generator . switch_to_basic_block ( loop_end ) ;
return { } ;
}
Bytecode : : CodeGenerationErrorOr < void > ForInStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
// 14.7.5.5 Runtime Semantics: ForInOfLoopEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-forinofloopevaluation
Bytecode : : CodeGenerationErrorOr < void > ForInStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < FlyString > const & label_set ) const
2022-03-18 20:18:19 +03:30
{
auto & loop_end = generator . make_block ( ) ;
auto & loop_update = generator . make_block ( ) ;
2022-06-11 23:09:37 +01:00
generator . begin_breakable_scope ( Bytecode : : Label { loop_end } , label_set ) ;
2022-03-18 20:18:19 +03:30
auto head_result = TRY ( for_in_of_head_evaluation ( generator , IterationKind : : Enumerate , m_lhs , m_rhs ) ) ;
// Now perform the rest of ForInOfLoopEvaluation, given that the accumulator holds the iterator we're supposed to iterate over.
2022-06-11 23:09:37 +01:00
return for_in_of_body_evaluation ( generator , * this , m_lhs , body ( ) , head_result , label_set , loop_end , loop_update ) ;
2022-03-18 20:18:19 +03:30
}
Bytecode : : CodeGenerationErrorOr < void > ForOfStatement : : generate_bytecode ( Bytecode : : Generator & generator ) const
2022-06-11 23:09:37 +01:00
{
return generate_labelled_evaluation ( generator , { } ) ;
}
Bytecode : : CodeGenerationErrorOr < void > ForOfStatement : : generate_labelled_evaluation ( Bytecode : : Generator & generator , Vector < FlyString > const & label_set ) const
2022-03-18 20:18:19 +03:30
{
auto & loop_end = generator . make_block ( ) ;
auto & loop_update = generator . make_block ( ) ;
2022-06-11 23:09:37 +01:00
generator . begin_breakable_scope ( Bytecode : : Label { loop_end } , label_set ) ;
2022-03-18 20:18:19 +03:30
auto head_result = TRY ( for_in_of_head_evaluation ( generator , IterationKind : : Iterate , m_lhs , m_rhs ) ) ;
// Now perform the rest of ForInOfLoopEvaluation, given that the accumulator holds the iterator we're supposed to iterate over.
2022-06-11 23:09:37 +01:00
return for_in_of_body_evaluation ( generator , * this , m_lhs , body ( ) , head_result , label_set , loop_end , loop_update ) ;
2022-03-18 20:18:19 +03:30
}
2022-03-19 19:40:21 +00:00
// 13.3.12.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation
Bytecode : : CodeGenerationErrorOr < void > MetaProperty : : generate_bytecode ( Bytecode : : Generator & generator ) const
{
// NewTarget : new . target
if ( m_type = = MetaProperty : : Type : : NewTarget ) {
// 1. Return GetNewTarget().
generator . emit < Bytecode : : Op : : GetNewTarget > ( ) ;
return { } ;
}
// ImportMeta : import . meta
if ( m_type = = MetaProperty : : Type : : ImportMeta ) {
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented meta property: import.meta " sv ,
} ;
}
VERIFY_NOT_REACHED ( ) ;
}
2021-06-04 11:31:13 +02:00
}