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 , { } , { } ) ;
if ( is < BlockStatement > ( * this ) | | is < SwitchStatement > ( * this ) ) {
// 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 ) ;
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 ) ;
auto const & name = function_declaration . name ( ) ;
auto index = generator . intern_identifier ( name ) ;
generator . emit < Bytecode : : Op : : NewFunction > ( function_declaration ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( index , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize ) ;
}
return { } ;
} ) ;
} 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).
generator . emit < Bytecode : : Op : : CreateVariable > ( index , Bytecode : : Op : : EnvironmentMode : : Var , false ) ;
2022-03-13 12:43:45 +03:30
generator . emit < Bytecode : : Op : : LoadImmediate > ( js_undefined ( ) ) ;
generator . emit < Bytecode : : Op : : SetVariable > ( index , Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize , Bytecode : : Op : : EnvironmentMode : : Var ) ;
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).
// v. Return NormalCompletion(empty).
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
// a. Perform ? env.CreateGlobalVarBinding(vn, false).
for ( auto & var_name : declared_var_names )
generator . register_binding ( generator . intern_identifier ( var_name ) , Bytecode : : Generator : : BindingMode : : Var ) ;
} 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-02-12 19:54:08 +03:30
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 :
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 ;
2021-06-07 19:53:47 +01:00
default :
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented operation " sv ,
} ;
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-02-12 19:54:08 +03:30
Bytecode : : CodeGenerationErrorOr < void > WhileStatement : : generate_bytecode ( Bytecode : : Generator & generator ) 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 ) ;
generator . begin_continuable_scope ( Bytecode : : Label { test_block } ) ;
2021-06-10 20:28:43 +08:00
generator . begin_breakable_scope ( Bytecode : : Label { end_block } ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
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 } ,
{ } ) ;
generator . end_continuable_scope ( ) ;
2021-06-10 20:28:43 +08:00
generator . end_breakable_scope ( ) ;
2021-06-09 19:57:18 +02: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
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 ) ;
generator . begin_continuable_scope ( Bytecode : : Label { test_block } ) ;
2021-06-10 20:28:43 +08:00
generator . begin_breakable_scope ( Bytecode : : Label { end_block } ) ;
2022-02-12 19:54:08 +03:30
TRY ( m_body - > generate_bytecode ( generator ) ) ;
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 } ,
{ } ) ;
generator . end_continuable_scope ( ) ;
2021-06-10 20:28:43 +08:00
generator . end_breakable_scope ( ) ;
2021-06-09 19:57:18 +02: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
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
2021-06-07 20:58:36 -07:00
if ( m_init )
2022-02-12 19:54:08 +03:30
TRY ( m_init - > generate_bytecode ( generator ) ) ;
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 ) ;
generator . begin_continuable_scope ( Bytecode : : Label { * update_block_ptr } ) ;
2021-06-10 20:28:43 +08:00
generator . begin_breakable_scope ( Bytecode : : Label { end_block } ) ;
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
{ } ) ;
2021-06-10 20:28:43 +08:00
generator . end_breakable_scope ( ) ;
2021-06-09 19:57:18 +02:00
generator . switch_to_basic_block ( end_block ) ;
generator . emit < Bytecode : : Op : : Load > ( result_reg ) ;
2021-06-09 06:49:58 +04:30
}
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 ) {
if ( property . type ( ) ! = ObjectProperty : : Type : : KeyValue )
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented property kind " sv ,
} ;
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-02-12 19:54:08 +03:30
TRY ( property . value ( ) . generate_bytecode ( generator ) ) ;
2021-06-11 19:40:48 +03:00
generator . emit < Bytecode : : Op : : PutById > ( object_reg , key_name ) ;
} 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-02-12 19:54:08 +03:30
TRY ( property . value ( ) . generate_bytecode ( generator ) ) ;
2021-06-11 19:40:48 +03:00
generator . emit < Bytecode : : Op : : PutByValue > ( object_reg , property_reg ) ;
}
}
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 ;
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
if ( is < SpreadExpression > ( * element ) ) {
2022-02-12 19:54:08 +03:30
return Bytecode : : CodeGenerationError {
this ,
" Unimplemented element kind: SpreadExpression " sv ,
} ;
2021-06-08 23:06:52 +02:00
}
2021-06-09 04:43:13 +01:00
} else {
generator . emit < Bytecode : : Op : : LoadImmediate > ( Value { } ) ;
2021-06-08 23:06:52 +02:00
}
auto element_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( element_reg ) ;
element_regs . append ( element_reg ) ;
}
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( element_regs . size ( ) , element_regs ) ;
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
{
generator . emit < Bytecode : : Op : : NewFunction > ( * this ) ;
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
2021-10-24 15:34:30 +02: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 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 > {
return Bytecode : : CodeGenerationError {
expr . ptr ( ) ,
" Unimplemented alias mode: MemberExpression " sv ,
} ;
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-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-02-12 19:54:08 +03:30
auto initialization_mode = is_lexical_declaration ( ) ? Bytecode : : Op : : SetVariable : : InitializationMode : : Initialize : Bytecode : : Op : : SetVariable : : InitializationMode : : Set ;
2022-03-13 12:43:45 +03:30
auto environment_mode = is_lexical_declaration ( ) ? Bytecode : : Op : : EnvironmentMode : : Lexical : Bytecode : : Op : : EnvironmentMode : : Var ;
2022-02-12 19:54:08 +03:30
TRY ( declarator . target ( ) . visit (
[ & ] ( NonnullRefPtr < Identifier > const & id ) - > Bytecode : : CodeGenerationErrorOr < void > {
2022-03-13 12:43:45 +03:30
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( id - > string ( ) ) , initialization_mode , environment_mode ) ;
2022-02-12 19:54:08 +03:30
return { } ;
2021-06-10 22:12:21 +02:00
} ,
2022-02-12 19:54:08 +03:30
[ & ] ( NonnullRefPtr < BindingPattern > const & pattern ) - > Bytecode : : CodeGenerationErrorOr < void > {
2021-06-13 12:24:55 -07:00
auto value_register = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( value_register ) ;
2022-02-12 19:54:08 +03:30
return generate_binding_pattern_bytecode ( generator , pattern , initialization_mode , value_register ) ;
} ) ) ;
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 ) ) {
auto & member_expression = static_cast < const MemberExpression & > ( * m_callee ) ;
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 ) ) ;
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-03-13 11:51:02 +03:30
generator . perform_needed_unwinds < Bytecode : : Op : : Jump > ( ) ;
2021-06-09 06:49:58 +04:30
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
generator . nearest_continuable_scope ( ) ,
{ } ) ;
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 ( ) ;
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 ) ;
string_regs . append ( string_reg ) ;
}
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( string_regs . size ( ) , string_regs ) ;
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 ;
for ( auto & raw_string : m_template_literal - > raw_strings ( ) ) {
2022-02-12 19:54:08 +03:30
TRY ( raw_string . generate_bytecode ( generator ) ) ;
2021-06-09 21:02:24 +02:00
auto raw_string_reg = generator . allocate_register ( ) ;
generator . emit < Bytecode : : Op : : Store > ( raw_string_reg ) ;
raw_string_regs . append ( raw_string_reg ) ;
}
generator . emit_with_extra_register_slots < Bytecode : : Op : : NewArray > ( raw_string_regs . size ( ) , raw_string_regs ) ;
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 ) ) ;
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-03-13 11:51:02 +03:30
generator . perform_needed_unwinds < Bytecode : : Op : : Jump > ( true ) ;
2021-06-10 20:28:43 +08:00
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets (
generator . nearest_breakable_scope ( ) ,
{ } ) ;
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-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 ( ) ) {
2021-07-11 15:15:38 +04:30
// FIXME: We need a separate DeclarativeEnvironment here
2021-10-24 15:34:30 +02:00
generator . emit < Bytecode : : Op : : SetVariable > ( generator . intern_identifier ( parameter ) ) ;
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 } ;
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
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 ( ) ;
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { * next_test_block } , { } ) ;
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 ( ) ;
generator . begin_breakable_scope ( Bytecode : : Label { end_block } ) ;
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 ) ) ;
2021-06-11 00:36:16 +02:00
}
if ( ! generator . is_current_block_terminated ( ) ) {
auto next_block = current_block ;
next_block + + ;
if ( next_block . is_end ( ) ) {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { end_block } , { } ) ;
} else {
generator . emit < Bytecode : : Op : : Jump > ( ) . set_targets ( Bytecode : : Label { * next_block } , { } ) ;
}
}
current_block + + ;
}
generator . end_breakable_scope ( ) ;
generator . switch_to_basic_block ( end_block ) ;
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 > ( ) ;
TRY ( m_body - > generate_bytecode ( generator ) ) ;
generator . emit < Bytecode : : Op : : LeaveEnvironment > ( Bytecode : : Op : : EnvironmentMode : : Lexical ) ;
return { } ;
}
2021-06-04 11:31:13 +02:00
}