@ -1,6 +1,6 @@
use crate ::{
use crate ::{
builtins ::function ::ThisMode ,
builtins ::function ::ThisMode ,
environments ::BindingLocator ,
environments ::{ BindingLocator , CompileTimeEnvironment } ,
syntax ::ast ::{
syntax ::ast ::{
node ::{
node ::{
declaration ::{
declaration ::{
@ -19,7 +19,7 @@ use crate::{
vm ::{ BindingOpcode , CodeBlock , Opcode } ,
vm ::{ BindingOpcode , CodeBlock , Opcode } ,
Context , JsBigInt , JsResult , JsString , JsValue ,
Context , JsBigInt , JsResult , JsString , JsValue ,
} ;
} ;
use boa_gc ::Gc ;
use boa_gc ::{ Cell , Gc } ;
use boa_interner ::{ Interner , Sym } ;
use boa_interner ::{ Interner , Sym } ;
use rustc_hash ::FxHashMap ;
use rustc_hash ::FxHashMap ;
use std ::mem ::size_of ;
use std ::mem ::size_of ;
@ -95,6 +95,14 @@ impl<'b> ByteCompiler<'b> {
self . context . interner ( )
self . context . interner ( )
}
}
/// Push a compile time environment to the current `CodeBlock` and return it's index.
#[ inline ]
fn push_compile_environment ( & mut self , environment : Gc < Cell < CompileTimeEnvironment > > ) -> usize {
let index = self . code_block . compile_environments . len ( ) ;
self . code_block . compile_environments . push ( environment ) ;
index
}
#[ inline ]
#[ inline ]
fn get_or_insert_literal ( & mut self , literal : Literal ) -> u32 {
fn get_or_insert_literal ( & mut self , literal : Literal ) -> u32 {
if let Some ( index ) = self . literals_map . get ( & literal ) {
if let Some ( index ) = self . literals_map . get ( & literal ) {
@ -281,13 +289,24 @@ impl<'b> ByteCompiler<'b> {
Label { index }
Label { index }
}
}
/// Emit an opcode with a dummy operand.
/// Return the `Label` of the operand.
#[ inline ]
#[ inline ]
fn jump_with_custom_opcode ( & mut self , opcode : Opcode ) -> Label {
fn emit_opcode_with_operand ( & mut self , opcode : Opcode ) -> Label {
let index = self . next_opcode_location ( ) ;
let index = self . next_opcode_location ( ) ;
self . emit ( opcode , & [ Self ::DUMMY_ADDRESS ] ) ;
self . emit ( opcode , & [ Self ::DUMMY_ADDRESS ] ) ;
Label { index }
Label { index }
}
}
/// Emit an opcode with two dummy operands.
/// Return the `Label`s of the two operands.
#[ inline ]
fn emit_opcode_with_two_operands ( & mut self , opcode : Opcode ) -> ( Label , Label ) {
let index = self . next_opcode_location ( ) ;
self . emit ( opcode , & [ Self ::DUMMY_ADDRESS , Self ::DUMMY_ADDRESS ] ) ;
( Label { index } , Label { index : index + 4 } )
}
#[ inline ]
#[ inline ]
fn patch_jump_with_target ( & mut self , label : Label , target : u32 ) {
fn patch_jump_with_target ( & mut self , label : Label , target : u32 ) {
let Label { index } = label ;
let Label { index } = label ;
@ -551,6 +570,35 @@ impl<'b> ByteCompiler<'b> {
Ok ( ( ) )
Ok ( ( ) )
}
}
/// Compile a statement list in a new declarative environment.
#[ inline ]
pub ( crate ) fn compile_statement_list_with_new_declarative (
& mut self ,
list : & [ Node ] ,
use_expr : bool ,
strict : bool ,
) -> JsResult < ( ) > {
self . context . push_compile_time_environment ( strict ) ;
let push_env = self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . create_declarations ( list ) ? ;
if let Some ( ( last , items ) ) = list . split_last ( ) {
for node in items {
self . compile_stmt ( node , false ) ? ;
}
self . compile_stmt ( last , use_expr ) ? ;
}
let ( num_bindings , compile_environment ) = self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
Ok ( ( ) )
}
#[ inline ]
#[ inline ]
pub fn compile_expr ( & mut self , expr : & Node , use_expr : bool ) -> JsResult < ( ) > {
pub fn compile_expr ( & mut self , expr : & Node , use_expr : bool ) -> JsResult < ( ) > {
match expr {
match expr {
@ -726,17 +774,17 @@ impl<'b> ByteCompiler<'b> {
BinOp ::Log ( op ) = > {
BinOp ::Log ( op ) = > {
match op {
match op {
LogOp ::And = > {
LogOp ::And = > {
let exit = self . jump_with_custom_opcode ( Opcode ::LogicalAnd ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::LogicalAnd ) ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
self . patch_jump ( exit ) ;
self . patch_jump ( exit ) ;
}
}
LogOp ::Or = > {
LogOp ::Or = > {
let exit = self . jump_with_custom_opcode ( Opcode ::LogicalOr ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::LogicalOr ) ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
self . patch_jump ( exit ) ;
self . patch_jump ( exit ) ;
}
}
LogOp ::Coalesce = > {
LogOp ::Coalesce = > {
let exit = self . jump_with_custom_opcode ( Opcode ::Coalesce ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::Coalesce ) ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
self . patch_jump ( exit ) ;
self . patch_jump ( exit ) ;
}
}
@ -761,7 +809,7 @@ impl<'b> ByteCompiler<'b> {
AssignOp ::Shr = > Some ( Opcode ::ShiftRight ) ,
AssignOp ::Shr = > Some ( Opcode ::ShiftRight ) ,
AssignOp ::Ushr = > Some ( Opcode ::UnsignedShiftRight ) ,
AssignOp ::Ushr = > Some ( Opcode ::UnsignedShiftRight ) ,
AssignOp ::BoolAnd = > {
AssignOp ::BoolAnd = > {
let exit = self . jump_with_custom_opcode ( Opcode ::LogicalAnd ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::LogicalAnd ) ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
let access =
let access =
Self ::compile_access ( binary . lhs ( ) ) . ok_or_else ( | | {
Self ::compile_access ( binary . lhs ( ) ) . ok_or_else ( | | {
@ -774,7 +822,7 @@ impl<'b> ByteCompiler<'b> {
None
None
}
}
AssignOp ::BoolOr = > {
AssignOp ::BoolOr = > {
let exit = self . jump_with_custom_opcode ( Opcode ::LogicalOr ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::LogicalOr ) ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
let access =
let access =
Self ::compile_access ( binary . lhs ( ) ) . ok_or_else ( | | {
Self ::compile_access ( binary . lhs ( ) ) . ok_or_else ( | | {
@ -787,7 +835,7 @@ impl<'b> ByteCompiler<'b> {
None
None
}
}
AssignOp ::Coalesce = > {
AssignOp ::Coalesce = > {
let exit = self . jump_with_custom_opcode ( Opcode ::Coalesce ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::Coalesce ) ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
self . compile_expr ( binary . rhs ( ) , true ) ? ;
let access =
let access =
Self ::compile_access ( binary . lhs ( ) ) . ok_or_else ( | | {
Self ::compile_access ( binary . lhs ( ) ) . ok_or_else ( | | {
@ -1067,7 +1115,7 @@ impl<'b> ByteCompiler<'b> {
self . emit_opcode ( Opcode ::InitIterator ) ;
self . emit_opcode ( Opcode ::InitIterator ) ;
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::PushUndefined ) ;
let start_address = self . next_opcode_location ( ) ;
let start_address = self . next_opcode_location ( ) ;
let start = self . jump_with_custom_opcode ( Opcode ::GeneratorNextDelegate ) ;
let start = self . emit_opcode_with_operand ( Opcode ::GeneratorNextDelegate ) ;
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
self . patch_jump ( start ) ;
self . patch_jump ( start ) ;
} else {
} else {
@ -1260,7 +1308,8 @@ impl<'b> ByteCompiler<'b> {
}
}
Node ::ForLoop ( for_loop ) = > {
Node ::ForLoop ( for_loop ) = > {
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env = self . jump_with_custom_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let push_env =
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
if let Some ( init ) = for_loop . init ( ) {
if let Some ( init ) = for_loop . init ( ) {
self . create_decls_from_stmt ( init ) ? ;
self . create_decls_from_stmt ( init ) ? ;
@ -1298,13 +1347,16 @@ impl<'b> ByteCompiler<'b> {
self . pop_loop_control_info ( ) ;
self . pop_loop_control_info ( ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
let num_bindings = self . context . pop_compile_time_environment ( ) . num_bindings ( ) ;
let ( num_bindings , compile_environment ) =
self . patch_jump_with_target ( push_env , num_bindings as u32 ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
}
}
Node ::ForInLoop ( for_in_loop ) = > {
Node ::ForInLoop ( for_in_loop ) = > {
self . compile_expr ( for_in_loop . expr ( ) , true ) ? ;
self . compile_expr ( for_in_loop . expr ( ) , true ) ? ;
let early_exit = self . jump_with_custom_opcode ( Opcode ::ForInLoopInitIterator ) ;
let early_exit = self . emit_opcode_with_operand ( Opcode ::ForInLoopInitIterator ) ;
self . emit_opcode ( Opcode ::LoopStart ) ;
self . emit_opcode ( Opcode ::LoopStart ) ;
let start_address = self . next_opcode_location ( ) ;
let start_address = self . next_opcode_location ( ) ;
@ -1312,8 +1364,9 @@ impl<'b> ByteCompiler<'b> {
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env = self . jump_with_custom_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let push_env =
let exit = self . jump_with_custom_opcode ( Opcode ::ForInLoopNext ) ;
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::ForInLoopNext ) ;
match for_in_loop . init ( ) {
match for_in_loop . init ( ) {
IterableLoopInitializer ::Identifier ( ref ident ) = > {
IterableLoopInitializer ::Identifier ( ref ident ) = > {
@ -1368,8 +1421,11 @@ impl<'b> ByteCompiler<'b> {
self . compile_stmt ( for_in_loop . body ( ) , false ) ? ;
self . compile_stmt ( for_in_loop . body ( ) , false ) ? ;
let num_bindings = self . context . pop_compile_time_environment ( ) . num_bindings ( ) ;
let ( num_bindings , compile_environment ) =
self . patch_jump_with_target ( push_env , num_bindings as u32 ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
@ -1392,8 +1448,9 @@ impl<'b> ByteCompiler<'b> {
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env = self . jump_with_custom_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let push_env =
let exit = self . jump_with_custom_opcode ( Opcode ::ForInLoopNext ) ;
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::ForInLoopNext ) ;
match for_of_loop . init ( ) {
match for_of_loop . init ( ) {
IterableLoopInitializer ::Identifier ( ref ident ) = > {
IterableLoopInitializer ::Identifier ( ref ident ) = > {
@ -1448,8 +1505,11 @@ impl<'b> ByteCompiler<'b> {
self . compile_stmt ( for_of_loop . body ( ) , false ) ? ;
self . compile_stmt ( for_of_loop . body ( ) , false ) ? ;
let num_bindings = self . context . pop_compile_time_environment ( ) . num_bindings ( ) ;
let ( num_bindings , compile_environment ) =
self . patch_jump_with_target ( push_env , num_bindings as u32 ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
@ -1623,11 +1683,15 @@ impl<'b> ByteCompiler<'b> {
}
}
Node ::Block ( block ) = > {
Node ::Block ( block ) = > {
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env = self . jump_with_custom_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let push_env =
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . create_declarations ( block . items ( ) ) ? ;
self . create_declarations ( block . items ( ) ) ? ;
self . compile_statement_list ( block . items ( ) , use_expr ) ? ;
self . compile_statement_list ( block . items ( ) , use_expr ) ? ;
let num_bindings = self . context . pop_compile_time_environment ( ) . num_bindings ( ) ;
let ( num_bindings , compile_environment ) =
self . patch_jump_with_target ( push_env , num_bindings as u32 ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
}
}
Node ::Throw ( throw ) = > {
Node ::Throw ( throw ) = > {
@ -1636,7 +1700,8 @@ impl<'b> ByteCompiler<'b> {
}
}
Node ::Switch ( switch ) = > {
Node ::Switch ( switch ) = > {
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env = self . jump_with_custom_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let push_env =
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
for case in switch . cases ( ) {
for case in switch . cases ( ) {
self . create_declarations ( case . body ( ) . items ( ) ) ? ;
self . create_declarations ( case . body ( ) . items ( ) ) ? ;
}
}
@ -1649,10 +1714,10 @@ impl<'b> ByteCompiler<'b> {
let mut labels = Vec ::with_capacity ( switch . cases ( ) . len ( ) ) ;
let mut labels = Vec ::with_capacity ( switch . cases ( ) . len ( ) ) ;
for case in switch . cases ( ) {
for case in switch . cases ( ) {
self . compile_expr ( case . condition ( ) , true ) ? ;
self . compile_expr ( case . condition ( ) , true ) ? ;
labels . push ( self . jump_with_custom_opcode ( Opcode ::Case ) ) ;
labels . push ( self . emit_opcode_with_operand ( Opcode ::Case ) ) ;
}
}
let exit = self . jump_with_custom_opcode ( Opcode ::Default ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::Default ) ;
for ( label , case ) in labels . into_iter ( ) . zip ( switch . cases ( ) ) {
for ( label , case ) in labels . into_iter ( ) . zip ( switch . cases ( ) ) {
self . patch_jump ( label ) ;
self . patch_jump ( label ) ;
@ -1668,8 +1733,12 @@ impl<'b> ByteCompiler<'b> {
self . pop_switch_control_info ( ) ;
self . pop_switch_control_info ( ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
let num_bindings = self . context . pop_compile_time_environment ( ) . num_bindings ( ) ;
self . patch_jump_with_target ( push_env , num_bindings as u32 ) ;
let ( num_bindings , compile_environment ) =
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
}
}
Node ::FunctionDecl ( _function ) = > self . function ( node , false ) ? ,
Node ::FunctionDecl ( _function ) = > self . function ( node , false ) ? ,
@ -1686,13 +1755,17 @@ impl<'b> ByteCompiler<'b> {
let try_start = self . next_opcode_location ( ) ;
let try_start = self . next_opcode_location ( ) ;
self . emit ( Opcode ::TryStart , & [ Self ::DUMMY_ADDRESS , 0 ] ) ;
self . emit ( Opcode ::TryStart , & [ Self ::DUMMY_ADDRESS , 0 ] ) ;
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env = self . jump_with_custom_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let push_env =
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . create_declarations ( t . block ( ) . items ( ) ) ? ;
self . create_declarations ( t . block ( ) . items ( ) ) ? ;
self . compile_statement_list ( t . block ( ) . items ( ) , use_expr ) ? ;
self . compile_statement_list ( t . block ( ) . items ( ) , use_expr ) ? ;
let num_bindings = self . context . pop_compile_time_environment ( ) . num_bindings ( ) ;
let ( num_bindings , compile_environment ) =
self . patch_jump_with_target ( push_env , num_bindings as u32 ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::TryEnd ) ;
self . emit_opcode ( Opcode ::TryEnd ) ;
@ -1702,12 +1775,13 @@ impl<'b> ByteCompiler<'b> {
if let Some ( catch ) = t . catch ( ) {
if let Some ( catch ) = t . catch ( ) {
self . push_try_control_info_catch_start ( ) ;
self . push_try_control_info_catch_start ( ) ;
let catch_start = if t . finally ( ) . is_some ( ) {
let catch_start = if t . finally ( ) . is_some ( ) {
Some ( self . jump_with_custom_opcode ( Opcode ::CatchStart ) )
Some ( self . emit_opcode_with_operand ( Opcode ::CatchStart ) )
} else {
} else {
None
None
} ;
} ;
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env = self . jump_with_custom_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let push_env =
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
if let Some ( decl ) = catch . parameter ( ) {
if let Some ( decl ) = catch . parameter ( ) {
match decl {
match decl {
Declaration ::Identifier { ident , .. } = > {
Declaration ::Identifier { ident , .. } = > {
@ -1728,8 +1802,12 @@ impl<'b> ByteCompiler<'b> {
self . create_declarations ( catch . block ( ) . items ( ) ) ? ;
self . create_declarations ( catch . block ( ) . items ( ) ) ? ;
self . compile_statement_list ( catch . block ( ) . items ( ) , use_expr ) ? ;
self . compile_statement_list ( catch . block ( ) . items ( ) , use_expr ) ? ;
let num_bindings = self . context . pop_compile_time_environment ( ) . num_bindings ( ) ;
let ( num_bindings , compile_environment ) =
self . patch_jump_with_target ( push_env , num_bindings as u32 ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment =
self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
if let Some ( catch_start ) = catch_start {
if let Some ( catch_start ) = catch_start {
self . emit_opcode ( Opcode ::CatchEnd ) ;
self . emit_opcode ( Opcode ::CatchEnd ) ;
@ -1755,13 +1833,18 @@ impl<'b> ByteCompiler<'b> {
) ;
) ;
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env = self . jump_with_custom_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let push_env =
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . create_declarations ( finally . items ( ) ) ? ;
self . create_declarations ( finally . items ( ) ) ? ;
self . compile_statement_list ( finally . items ( ) , false ) ? ;
self . compile_statement_list ( finally . items ( ) , false ) ? ;
let num_bindings = self . context . pop_compile_time_environment ( ) . num_bindings ( ) ;
let ( num_bindings , compile_environment ) =
self . patch_jump_with_target ( push_env , num_bindings as u32 ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment =
self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::FinallyEnd ) ;
self . emit_opcode ( Opcode ::FinallyEnd ) ;
@ -1879,7 +1962,7 @@ impl<'b> ByteCompiler<'b> {
Declaration ::Identifier { ident , .. } = > {
Declaration ::Identifier { ident , .. } = > {
compiler . context . create_mutable_binding ( ident . sym ( ) , false ) ;
compiler . context . create_mutable_binding ( ident . sym ( ) , false ) ;
if let Some ( init ) = parameter . declaration ( ) . init ( ) {
if let Some ( init ) = parameter . declaration ( ) . init ( ) {
let skip = compiler . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
let skip = compiler . emit_opcode_with_operand ( Opcode ::JumpIfNotUndefined ) ;
compiler . compile_expr ( init , true ) ? ;
compiler . compile_expr ( init , true ) ? ;
compiler . patch_jump ( skip ) ;
compiler . patch_jump ( skip ) ;
}
}
@ -1901,7 +1984,7 @@ impl<'b> ByteCompiler<'b> {
let env_label = if parameters . has_expressions ( ) {
let env_label = if parameters . has_expressions ( ) {
compiler . code_block . num_bindings = compiler . context . get_binding_number ( ) ;
compiler . code_block . num_bindings = compiler . context . get_binding_number ( ) ;
compiler . context . push_compile_time_environment ( true ) ;
compiler . context . push_compile_time_environment ( true ) ;
Some ( compiler . jump_with_custom_opcode ( Opcode ::PushFunctionEnvironment ) )
Some ( compiler . emit_opcode_with_two_operands ( Opcode ::PushFunctionEnvironment ) )
} else {
} else {
None
None
} ;
} ;
@ -1916,17 +1999,22 @@ impl<'b> ByteCompiler<'b> {
compiler . compile_statement_list ( body . items ( ) , false ) ? ;
compiler . compile_statement_list ( body . items ( ) , false ) ? ;
if let Some ( env_label ) = env_label {
if let Some ( env_label ) = env_label {
let num_bindings = compiler
let ( num_bindings , compile_environment ) =
. context
compiler . context . pop_compile_time_environment ( ) ;
. pop_compile_time_environment ( )
let index_compile_environment = compiler . push_compile_environment ( compile_environment ) ;
. num_bindings ( ) ;
compiler . patch_jump_with_target ( env_label . 0 , num_bindings as u32 ) ;
compiler . patch_jump_with_target ( env_label , num_bindings as u32 ) ;
compiler . patch_jump_with_target ( env_label . 1 , index_compile_environment as u32 ) ;
compiler . context . pop_compile_time_environment ( ) ;
let ( _ , compile_environment ) = compiler . context . pop_compile_time_environment ( ) ;
compiler . push_compile_environment ( compile_environment ) ;
} else {
} else {
compiler . code_block . num_bindings = compiler
let ( num_bindings , compile_environment ) =
. context
compiler . context . pop_compile_time_environment ( ) ;
. pop_compile_time_environment ( )
compiler
. num_bindings ( ) ;
. code_block
. compile_environments
. push ( compile_environment ) ;
compiler . code_block . num_bindings = num_bindings ;
}
}
compiler . code_block . params = parameters . clone ( ) ;
compiler . code_block . params = parameters . clone ( ) ;
@ -1966,12 +2054,16 @@ impl<'b> ByteCompiler<'b> {
pub ( crate ) fn call ( & mut self , node : & Node , use_expr : bool ) -> JsResult < ( ) > {
pub ( crate ) fn call ( & mut self , node : & Node , use_expr : bool ) -> JsResult < ( ) > {
#[ derive(PartialEq) ]
#[ derive(PartialEq) ]
enum CallKind {
enum CallKind {
CallEval ,
Call ,
Call ,
New ,
New ,
}
}
let ( call , kind ) = match node {
let ( call , kind ) = match node {
Node ::Call ( call ) = > ( call , CallKind ::Call ) ,
Node ::Call ( call ) = > match call . expr ( ) {
Node ::Identifier ( ident ) if ident . sym ( ) = = Sym ::EVAL = > ( call , CallKind ::CallEval ) ,
_ = > ( call , CallKind ::Call ) ,
} ,
Node ::New ( new ) = > ( new . call ( ) , CallKind ::New ) ,
Node ::New ( new ) = > ( new . call ( ) , CallKind ::New ) ,
_ = > unreachable! ( ) ,
_ = > unreachable! ( ) ,
} ;
} ;
@ -1996,7 +2088,7 @@ impl<'b> ByteCompiler<'b> {
}
}
expr = > {
expr = > {
self . compile_expr ( expr , true ) ? ;
self . compile_expr ( expr , true ) ? ;
if kind = = CallKind ::Call {
if kind = = CallKind ::Call | | kind = = CallKind ::CallEval {
self . emit_opcode ( Opcode ::This ) ;
self . emit_opcode ( Opcode ::This ) ;
self . emit_opcode ( Opcode ::Swap ) ;
self . emit_opcode ( Opcode ::Swap ) ;
}
}
@ -2010,6 +2102,10 @@ impl<'b> ByteCompiler<'b> {
let last_is_rest_parameter = matches! ( call . args ( ) . last ( ) , Some ( Node ::Spread ( _ ) ) ) ;
let last_is_rest_parameter = matches! ( call . args ( ) . last ( ) , Some ( Node ::Spread ( _ ) ) ) ;
match kind {
match kind {
CallKind ::CallEval if last_is_rest_parameter = > {
self . emit ( Opcode ::CallEvalWithRest , & [ call . args ( ) . len ( ) as u32 ] ) ;
}
CallKind ::CallEval = > self . emit ( Opcode ::CallEval , & [ call . args ( ) . len ( ) as u32 ] ) ,
CallKind ::Call if last_is_rest_parameter = > {
CallKind ::Call if last_is_rest_parameter = > {
self . emit ( Opcode ::CallWithRest , & [ call . args ( ) . len ( ) as u32 ] ) ;
self . emit ( Opcode ::CallWithRest , & [ call . args ( ) . len ( ) as u32 ] ) ;
}
}
@ -2039,7 +2135,7 @@ impl<'b> ByteCompiler<'b> {
) -> JsResult < ( ) > {
) -> JsResult < ( ) > {
match pattern {
match pattern {
DeclarationPattern ::Object ( pattern ) = > {
DeclarationPattern ::Object ( pattern ) = > {
let skip_init = self . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
let skip_init = self . emit_opcode_with_operand ( Opcode ::JumpIfNotUndefined ) ;
if let Some ( init ) = pattern . init ( ) {
if let Some ( init ) = pattern . init ( ) {
self . compile_expr ( init , true ) ? ;
self . compile_expr ( init , true ) ? ;
} else {
} else {
@ -2078,7 +2174,8 @@ impl<'b> ByteCompiler<'b> {
}
}
if let Some ( init ) = default_init {
if let Some ( init ) = default_init {
let skip = self . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
let skip =
self . emit_opcode_with_operand ( Opcode ::JumpIfNotUndefined ) ;
self . compile_expr ( init , true ) ? ;
self . compile_expr ( init , true ) ? ;
self . patch_jump ( skip ) ;
self . patch_jump ( skip ) ;
}
}
@ -2140,7 +2237,8 @@ impl<'b> ByteCompiler<'b> {
}
}
if let Some ( init ) = default_init {
if let Some ( init ) = default_init {
let skip = self . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
let skip =
self . emit_opcode_with_operand ( Opcode ::JumpIfNotUndefined ) ;
self . compile_expr ( init , true ) ? ;
self . compile_expr ( init , true ) ? ;
self . patch_jump ( skip ) ;
self . patch_jump ( skip ) ;
}
}
@ -2153,7 +2251,7 @@ impl<'b> ByteCompiler<'b> {
self . emit_opcode ( Opcode ::Pop ) ;
self . emit_opcode ( Opcode ::Pop ) ;
}
}
DeclarationPattern ::Array ( pattern ) = > {
DeclarationPattern ::Array ( pattern ) = > {
let skip_init = self . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
let skip_init = self . emit_opcode_with_operand ( Opcode ::JumpIfNotUndefined ) ;
if let Some ( init ) = pattern . init ( ) {
if let Some ( init ) = pattern . init ( ) {
self . compile_expr ( init , true ) ? ;
self . compile_expr ( init , true ) ? ;
} else {
} else {
@ -2192,7 +2290,8 @@ impl<'b> ByteCompiler<'b> {
} = > {
} = > {
self . emit_opcode ( next ) ;
self . emit_opcode ( next ) ;
if let Some ( init ) = default_init {
if let Some ( init ) = default_init {
let skip = self . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
let skip =
self . emit_opcode_with_operand ( Opcode ::JumpIfNotUndefined ) ;
self . compile_expr ( init , true ) ? ;
self . compile_expr ( init , true ) ? ;
self . patch_jump ( skip ) ;
self . patch_jump ( skip ) ;
}
}
@ -2462,7 +2561,8 @@ impl<'b> ByteCompiler<'b> {
Declaration ::Identifier { ident , .. } = > {
Declaration ::Identifier { ident , .. } = > {
compiler . context . create_mutable_binding ( ident . sym ( ) , false ) ;
compiler . context . create_mutable_binding ( ident . sym ( ) , false ) ;
if let Some ( init ) = parameter . declaration ( ) . init ( ) {
if let Some ( init ) = parameter . declaration ( ) . init ( ) {
let skip = compiler . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
let skip =
compiler . emit_opcode_with_operand ( Opcode ::JumpIfNotUndefined ) ;
compiler . compile_expr ( init , true ) ? ;
compiler . compile_expr ( init , true ) ? ;
compiler . patch_jump ( skip ) ;
compiler . patch_jump ( skip ) ;
}
}
@ -2482,30 +2582,38 @@ impl<'b> ByteCompiler<'b> {
let env_label = if expr . parameters ( ) . has_expressions ( ) {
let env_label = if expr . parameters ( ) . has_expressions ( ) {
compiler . code_block . num_bindings = compiler . context . get_binding_number ( ) ;
compiler . code_block . num_bindings = compiler . context . get_binding_number ( ) ;
compiler . context . push_compile_time_environment ( true ) ;
compiler . context . push_compile_time_environment ( true ) ;
Some ( compiler . jump_with_custom_opcode ( Opcode ::PushFunctionEnvironment ) )
Some ( compiler . emit_opcode_with_two_operands ( Opcode ::PushFunctionEnvironment ) )
} else {
} else {
None
None
} ;
} ;
compiler . create_declarations ( expr . body ( ) . items ( ) ) ? ;
compiler . create_declarations ( expr . body ( ) . items ( ) ) ? ;
compiler . compile_statement_list ( expr . body ( ) . items ( ) , false ) ? ;
compiler . compile_statement_list ( expr . body ( ) . items ( ) , false ) ? ;
if let Some ( env_label ) = env_label {
if let Some ( env_label ) = env_label {
let num_bindings = compiler
let ( num_bindings , compile_environment ) =
. context
compiler . context . pop_compile_time_environment ( ) ;
. pop_compile_time_environment ( )
let index_compile_environment =
. num_bindings ( ) ;
compiler . push_compile_environment ( compile_environment ) ;
compiler . patch_jump_with_target ( env_label , num_bindings as u32 ) ;
compiler . patch_jump_with_target ( env_label . 0 , num_bindings as u32 ) ;
compiler . context . pop_compile_time_environment ( ) ;
compiler . patch_jump_with_target ( env_label . 1 , index_compile_environment as u32 ) ;
let ( _ , compile_environment ) = compiler . context . pop_compile_time_environment ( ) ;
compiler . push_compile_environment ( compile_environment ) ;
} else {
} else {
compiler . code_block . num_bindings = compiler
let ( num_bindings , compile_environment ) =
. context
compiler . context . pop_compile_time_environment ( ) ;
. pop_compile_time_environment ( )
compiler
. num_bindings ( ) ;
. code_block
. compile_environments
. push ( compile_environment ) ;
compiler . code_block . num_bindings = num_bindings ;
}
}
} else {
} else {
compiler . code_block . num_bindings = compiler
let ( num_bindings , compile_environment ) =
. context
compiler . context . pop_compile_time_environment ( ) ;
. pop_compile_time_environment ( )
compiler
. num_bindings ( ) ;
. code_block
. compile_environments
. push ( compile_environment ) ;
compiler . code_block . num_bindings = num_bindings ;
}
}
compiler . emit_opcode ( Opcode ::PushUndefined ) ;
compiler . emit_opcode ( Opcode ::PushUndefined ) ;
@ -2655,16 +2763,20 @@ impl<'b> ByteCompiler<'b> {
compiler . context . push_compile_time_environment ( true ) ;
compiler . context . push_compile_time_environment ( true ) ;
compiler . create_declarations ( statement_list . items ( ) ) ? ;
compiler . create_declarations ( statement_list . items ( ) ) ? ;
compiler . compile_statement_list ( statement_list . items ( ) , false ) ? ;
compiler . compile_statement_list ( statement_list . items ( ) , false ) ? ;
compiler . code_block . num_bindings = compiler
let ( num_bindings , compile_environment ) =
. context
compiler . context . pop_compile_time_environment ( ) ;
. pop_compile_time_environment ( )
compiler
. num_bindings ( ) ;
. code_block
. compile_environments
. push ( compile_environment ) ;
compiler . code_block . num_bindings = num_bindings ;
let code = Gc ::new ( compiler . finish ( ) ) ;
let code = Gc ::new ( compiler . finish ( ) ) ;
let index = self . code_block . functions . len ( ) as u32 ;
let index = self . code_block . functions . len ( ) as u32 ;
self . code_block . functions . push ( code ) ;
self . code_block . functions . push ( code ) ;
self . emit ( Opcode ::GetFunction , & [ index ] ) ;
self . emit ( Opcode ::GetFunction , & [ index ] ) ;
self . emit ( Opcode ::Call , & [ 0 ] ) ;
self . emit ( Opcode ::Call , & [ 0 ] ) ;
self . emit_opcode ( Opcode ::Pop ) ;
}
}
ClassElement ::MethodDefinition ( .. )
ClassElement ::MethodDefinition ( .. )
| ClassElement ::PrivateMethodDefinition ( .. )
| ClassElement ::PrivateMethodDefinition ( .. )