@ -16,7 +16,7 @@ use crate::{
vm ::{ CodeBlock , Opcode } ,
JsBigInt , JsString , JsValue ,
} ;
use std ::collections ::HashMap ;
use std ::{ collections ::HashMap , mem ::size_of } ;
#[ derive(Debug, Clone, PartialEq, Eq, Hash) ]
enum Literal {
@ -36,6 +36,8 @@ struct JumpControlInfo {
start_address : u32 ,
kind : JumpControlInfoKind ,
breaks : Vec < Label > ,
try_continues : Vec < Label > ,
for_of_in_loop : bool ,
}
#[ derive(Debug, Clone, PartialEq) ]
@ -58,9 +60,7 @@ pub struct ByteCompiler {
code_block : CodeBlock ,
literals_map : HashMap < Literal , u32 > ,
names_map : HashMap < JsString , u32 > ,
functions_map : HashMap < JsString , u32 > ,
jump_info : Vec < JumpControlInfo > ,
top_level : bool ,
}
impl ByteCompiler {
@ -73,9 +73,7 @@ impl ByteCompiler {
code_block : CodeBlock ::new ( name , 0 , strict , false ) ,
literals_map : HashMap ::new ( ) ,
names_map : HashMap ::new ( ) ,
functions_map : HashMap ::new ( ) ,
jump_info : Vec ::new ( ) ,
top_level : true ,
}
}
@ -243,6 +241,24 @@ impl ByteCompiler {
start_address ,
kind : JumpControlInfoKind ::Loop ,
breaks : Vec ::new ( ) ,
try_continues : Vec ::new ( ) ,
for_of_in_loop : false ,
} )
}
#[ inline ]
fn push_loop_control_info_for_of_in_loop (
& mut self ,
label : Option < Box < str > > ,
start_address : u32 ,
) {
self . jump_info . push ( JumpControlInfo {
label ,
start_address ,
kind : JumpControlInfoKind ::Loop ,
breaks : Vec ::new ( ) ,
try_continues : Vec ::new ( ) ,
for_of_in_loop : true ,
} )
}
@ -264,6 +280,8 @@ impl ByteCompiler {
start_address ,
kind : JumpControlInfoKind ::Switch ,
breaks : Vec ::new ( ) ,
try_continues : Vec ::new ( ) ,
for_of_in_loop : false ,
} )
}
@ -280,27 +298,45 @@ impl ByteCompiler {
#[ inline ]
fn push_try_control_info ( & mut self ) {
if ! self . jump_info . is_empty ( ) {
let start_address = self . jump_info . last ( ) . unwrap ( ) . start_address ;
self . jump_info . push ( JumpControlInfo {
label : None ,
start_address : u32 ::MAX ,
start_address ,
kind : JumpControlInfoKind ::Try ,
breaks : Vec ::new ( ) ,
try_continues : Vec ::new ( ) ,
for_of_in_loop : false ,
} )
}
}
#[ inline ]
fn pop_try_control_info ( & mut self , finally_start_address : Option < u32 > ) {
if ! self . jump_info . is_empty ( ) {
let mut info = self . jump_info . pop ( ) . unwrap ( ) ;
assert! ( info . kind = = JumpControlInfoKind ::Try ) ;
if let Some ( finally_start_address ) = finally_start_address {
let mut breaks = Vec ::with_capacity ( info . breaks . len ( ) ) ;
let finally_end = self . jump_with_custom_opcode ( Opcode ::FinallyJump ) ;
if let Some ( finally_start_address ) = finally_start_address {
for label in info . try_continues {
if label . index < finally_start_address {
self . patch_jump_with_target ( label , finally_start_address ) ;
} else {
self . patch_jump_with_target ( label , info . start_address )
}
}
for label in info . breaks {
if label . index < finally_start_address {
self . patch_jump_with_target ( label , finally_start_address ) ;
breaks . push ( finally_end ) ;
let Label { mut index } = label ;
index - = size_of ::< Opcode > ( ) as u32 ;
index - = size_of ::< u32 > ( ) as u32 ;
breaks . push ( Label { index } ) ;
} else {
breaks . push ( label ) ;
}
@ -312,6 +348,7 @@ impl ByteCompiler {
jump_info . breaks . append ( & mut info . breaks ) ;
}
}
}
#[ inline ]
fn compile_access < ' a > ( & mut self , node : & ' a Node ) -> Access < ' a > {
@ -475,7 +512,17 @@ impl ByteCompiler {
UnaryOp ::Plus = > Some ( Opcode ::Pos ) ,
UnaryOp ::Not = > Some ( Opcode ::LogicalNot ) ,
UnaryOp ::Tilde = > Some ( Opcode ::BitNot ) ,
UnaryOp ::TypeOf = > Some ( Opcode ::TypeOf ) ,
UnaryOp ::TypeOf = > {
match & unary . target ( ) {
Node ::Identifier ( identifier ) = > {
let index = self . get_or_insert_name ( identifier . as_ref ( ) ) ;
self . emit ( Opcode ::GetNameOrUndefined , & [ index ] ) ;
}
expr = > self . compile_expr ( expr , true ) ,
}
self . emit_opcode ( Opcode ::TypeOf ) ;
None
}
UnaryOp ::Void = > Some ( Opcode ::Void ) ,
} ;
@ -545,17 +592,12 @@ impl ByteCompiler {
LogOp ::And = > {
let exit = self . jump_with_custom_opcode ( Opcode ::LogicalAnd ) ;
self . compile_expr ( binary . rhs ( ) , true ) ;
self . emit ( Opcode ::ToBoolean , & [ ] ) ;
self . patch_jump ( exit ) ;
}
LogOp ::Or = > {
self . emit_opcode ( Opcode ::Dup ) ;
let exit = self . jump_with_custom_opcode ( Opcode ::LogicalOr ) ;
self . emit_opcode ( Opcode ::Pop ) ;
self . compile_expr ( binary . rhs ( ) , true ) ;
self . emit_opcode ( Opcode ::Dup ) ;
self . patch_jump ( exit ) ;
self . emit_opcode ( Opcode ::Pop ) ;
}
LogOp ::Coalesce = > {
let exit = self . jump_with_custom_opcode ( Opcode ::Coalesce ) ;
@ -585,24 +627,25 @@ impl ByteCompiler {
AssignOp ::BoolAnd = > {
let exit = self . jump_with_custom_opcode ( Opcode ::LogicalAnd ) ;
self . compile_expr ( binary . rhs ( ) , true ) ;
self . emit ( Opcode ::ToBoolean , & [ ] ) ;
let access = self . compile_access ( binary . lhs ( ) ) ;
self . access_set ( access , None , use_expr ) ;
self . patch_jump ( exit ) ;
None
}
AssignOp ::BoolOr = > {
let exit = self . jump_with_custom_opcode ( Opcode ::LogicalOr ) ;
self . compile_expr ( binary . rhs ( ) , true ) ;
self . emit ( Opcode ::ToBoolean , & [ ] ) ;
let access = self . compile_access ( binary . lhs ( ) ) ;
self . access_set ( access , None , use_expr ) ;
self . patch_jump ( exit ) ;
None
}
AssignOp ::Coalesce = > {
let exit = self . jump_with_custom_opcode ( Opcode ::Coalesce ) ;
self . compile_expr ( binary . rhs ( ) , true ) ;
let access = self . compile_access ( binary . lhs ( ) ) ;
self . access_set ( access , None , use_expr ) ;
self . patch_jump ( exit ) ;
None
}
} ;
@ -610,11 +653,10 @@ impl ByteCompiler {
if let Some ( opcode ) = opcode {
self . compile_expr ( binary . rhs ( ) , true ) ;
self . emit ( opcode , & [ ] ) ;
}
let access = self . compile_access ( binary . lhs ( ) ) ;
self . access_set ( access , None , use_expr ) ;
}
}
BinOp ::Comma = > {
self . emit ( Opcode ::Pop , & [ ] ) ;
self . compile_expr ( binary . rhs ( ) , true ) ;
@ -632,115 +674,107 @@ impl ByteCompiler {
match property {
PropertyDefinition ::IdentifierReference ( identifier_reference ) = > {
let index = self . get_or_insert_name ( identifier_reference ) ;
self . emit ( Opcode ::Set PropertyByName, & [ index ] ) ;
self . emit ( Opcode ::DefineOwn PropertyByName, & [ index ] ) ;
}
PropertyDefinition ::Property ( name , node ) = > {
PropertyDefinition ::Property ( name , node ) = > match name {
PropertyName ::Literal ( name ) = > {
self . compile_stmt ( node , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
match name {
PropertyName ::Literal ( name ) = > {
let index = self . get_or_insert_name ( name ) ;
self . emit ( Opcode ::Set PropertyByName, & [ index ] ) ;
self . emit ( Opcode ::DefineOwnPropertyByName , & [ index ] ) ;
}
PropertyName ::Computed ( name_node ) = > {
self . compile_stmt ( name_node , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
self . emit_opcode ( Opcode ::SetPropertyByValue ) ;
}
}
self . compile_stmt ( node , true ) ;
self . emit_opcode ( Opcode ::DefineOwnPropertyByValue ) ;
}
} ,
PropertyDefinition ::MethodDefinition ( kind , name , func ) = > {
match kind {
MethodDefinitionKind ::Get = > {
MethodDefinitionKind ::Get = > match name {
PropertyName ::Literal ( name ) = > {
self . compile_stmt ( & func . clone ( ) . into ( ) , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
match name {
PropertyName ::Literal ( name ) = > {
let index = self . get_or_insert_name ( name ) ;
self . emit ( Opcode ::SetPropertyGetterByName , & [ index ] ) ;
}
PropertyName ::Computed ( name_node ) = > {
self . compile_stmt ( name_node , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
self . compile_stmt ( & func . clone ( ) . into ( ) , true ) ;
self . emit_opcode ( Opcode ::SetPropertyGetterByValue ) ;
}
}
}
MethodDefinitionKind ::Set = > {
} ,
MethodDefinitionKind ::Set = > match name {
PropertyName ::Literal ( name ) = > {
self . compile_stmt ( & func . clone ( ) . into ( ) , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
match name {
PropertyName ::Literal ( name ) = > {
let index = self . get_or_insert_name ( name ) ;
self . emit ( Opcode ::SetPropertySetterByName , & [ index ] ) ;
}
PropertyName ::Computed ( name_node ) = > {
self . compile_stmt ( name_node , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
self . compile_stmt ( & func . clone ( ) . into ( ) , true ) ;
self . emit_opcode ( Opcode ::SetPropertySetterByValue ) ;
}
}
}
MethodDefinitionKind ::Ordinary = > {
} ,
MethodDefinitionKind ::Ordinary = > match name {
PropertyName ::Literal ( name ) = > {
self . compile_stmt ( & func . clone ( ) . into ( ) , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
match name {
PropertyName ::Literal ( name ) = > {
let index = self . get_or_insert_name ( name ) ;
self . emit ( Opcode ::Set PropertyByName, & [ index ] ) ;
self . emit ( Opcode ::DefineOwnPropertyByName , & [ index ] ) ;
}
PropertyName ::Computed ( name_node ) = > {
self . compile_stmt ( name_node , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
self . emit_opcode ( Opcode ::SetPropertyByValue ) ;
}
}
self . compile_stmt ( & func . clone ( ) . into ( ) , true ) ;
self . emit_opcode ( Opcode ::DefineOwnPropertyByValue ) ;
}
} ,
MethodDefinitionKind ::Generator = > {
// TODO: Implement generators
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::Swap ) ;
match name {
PropertyName ::Literal ( name ) = > {
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::Swap ) ;
let index = self . get_or_insert_name ( name ) ;
self . emit ( Opcode ::SetPropertyByName , & [ index ] ) ;
self . emit ( Opcode ::DefineOwn PropertyByName, & [ index ] ) ;
}
PropertyName ::Computed ( name_node ) = > {
self . compile_stmt ( name_node , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
self . emit_opcode ( Opcode ::Set PropertyByValue) ;
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::DefineOwn PropertyByValue) ;
}
}
}
MethodDefinitionKind ::Async = > {
// TODO: Implement async
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::Swap ) ;
match name {
PropertyName ::Literal ( name ) = > {
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::Swap ) ;
let index = self . get_or_insert_name ( name ) ;
self . emit ( Opcode ::SetPropertyByName , & [ index ] )
self . emit ( Opcode ::DefineOwn PropertyByName, & [ index ] )
}
PropertyName ::Computed ( name_node ) = > {
self . compile_stmt ( name_node , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
self . emit_opcode ( Opcode ::Set PropertyByValue) ;
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::DefineOwn PropertyByValue) ;
}
}
}
MethodDefinitionKind ::AsyncGenerator = > {
// TODO: Implement async generators
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::Swap ) ;
match name {
PropertyName ::Literal ( name ) = > {
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::Swap ) ;
let index = self . get_or_insert_name ( name ) ;
self . emit ( Opcode ::SetPropertyByName , & [ index ] )
self . emit ( Opcode ::DefineOwn PropertyByName, & [ index ] )
}
PropertyName ::Computed ( name_node ) = > {
self . compile_stmt ( name_node , true ) ;
self . emit_opcode ( Opcode ::Swap ) ;
self . emit_opcode ( Opcode ::Set PropertyByValue) ;
self . emit_opcode ( Opcode ::PushUndefined ) ;
self . emit_opcode ( Opcode ::DefineOwn PropertyByValue) ;
}
}
}
@ -765,9 +799,14 @@ impl ByteCompiler {
self . access_get ( access , use_expr ) ;
}
Node ::Assign ( assign ) = > {
// Implement destructing assignments like here: https://tc39.es/ecma262/#sec-destructuring-assignment
if let Node ::Object ( _ ) = assign . lhs ( ) {
self . emit_opcode ( Opcode ::PushUndefined ) ;
} else {
let access = self . compile_access ( assign . lhs ( ) ) ;
self . access_set ( access , Some ( assign . rhs ( ) ) , use_expr ) ;
}
}
Node ::GetConstField ( node ) = > {
let access = Access ::ByName { node } ;
self . access_get ( access , use_expr ) ;
@ -791,6 +830,7 @@ impl ByteCompiler {
}
Node ::ArrayDecl ( array ) = > {
self . emit_opcode ( Opcode ::PushNewArray ) ;
self . emit_opcode ( Opcode ::PopOnReturnAdd ) ;
for element in array . as_ref ( ) {
self . compile_expr ( element , true ) ;
@ -802,6 +842,7 @@ impl ByteCompiler {
}
}
self . emit_opcode ( Opcode ::PopOnReturnSub ) ;
if ! use_expr {
self . emit ( Opcode ::Pop , & [ ] ) ;
}
@ -815,7 +856,7 @@ impl ByteCompiler {
Node ::Call ( _ ) = > self . call ( expr , use_expr ) ,
Node ::New ( _ ) = > self . call ( expr , use_expr ) ,
Node ::TemplateLit ( template_literal ) = > {
for element in template_literal . elements ( ) . iter ( ) . rev ( ) {
for element in template_literal . elements ( ) {
match element {
TemplateElement ::String ( s ) = > {
self . emit_push_literal ( Literal ::String ( s . as_ref ( ) . into ( ) ) )
@ -877,16 +918,6 @@ impl ByteCompiler {
}
}
for expr in template . exprs ( ) . iter ( ) . rev ( ) {
self . compile_expr ( expr , true ) ;
}
self . emit_opcode ( Opcode ::PushNewArray ) ;
for raw in template . raws ( ) {
self . emit_push_literal ( Literal ::String ( raw . as_ref ( ) . into ( ) ) ) ;
self . emit_opcode ( Opcode ::PushValueToArray ) ;
}
self . emit_opcode ( Opcode ::PushNewArray ) ;
for cooked in template . cookeds ( ) {
if let Some ( cooked ) = cooked {
@ -896,11 +927,22 @@ impl ByteCompiler {
}
self . emit_opcode ( Opcode ::PushValueToArray ) ;
}
self . emit_opcode ( Opcode ::Dup ) ;
self . emit_opcode ( Opcode ::PushNewArray ) ;
for raw in template . raws ( ) {
self . emit_push_literal ( Literal ::String ( raw . as_ref ( ) . into ( ) ) ) ;
self . emit_opcode ( Opcode ::PushValueToArray ) ;
}
self . emit_opcode ( Opcode ::Swap ) ;
let index = self . get_or_insert_name ( "raw" ) ;
self . emit ( Opcode ::SetPropertyByName , & [ index ] ) ;
for expr in template . exprs ( ) {
self . compile_expr ( expr , true ) ;
}
self . emit ( Opcode ::Call , & [ ( template . exprs ( ) . len ( ) + 1 ) as u32 ] ) ;
}
_ = > unreachable! ( ) ,
@ -1064,7 +1106,10 @@ impl ByteCompiler {
let early_exit = self . jump_with_custom_opcode ( Opcode ::ForInLoopInitIterator ) ;
let start_address = self . next_opcode_location ( ) ;
self . push_loop_control_info ( for_in_loop . label ( ) . map ( Into ::into ) , start_address ) ;
self . push_loop_control_info_for_of_in_loop (
for_in_loop . label ( ) . map ( Into ::into ) ,
start_address ,
) ;
self . emit_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let exit = self . jump_with_custom_opcode ( Opcode ::ForInLoopNext ) ;
@ -1077,7 +1122,7 @@ impl ByteCompiler {
IterableLoopInitializer ::Var ( declaration ) = > match declaration {
Declaration ::Identifier { ident , .. } = > {
let index = self . get_or_insert_name ( ident . as_ref ( ) ) ;
self . emit ( Opcode ::SetName , & [ index ] ) ;
self . emit ( Opcode ::DefInitVar , & [ index ] ) ;
}
Declaration ::Pattern ( pattern ) = > {
self . compile_declaration_pattern ( pattern , Opcode ::DefInitVar ) ;
@ -1086,7 +1131,7 @@ impl ByteCompiler {
IterableLoopInitializer ::Let ( declaration ) = > match declaration {
Declaration ::Identifier { ident , .. } = > {
let index = self . get_or_insert_name ( ident . as_ref ( ) ) ;
self . emit ( Opcode ::SetName , & [ index ] ) ;
self . emit ( Opcode ::DefInitLet , & [ index ] ) ;
}
Declaration ::Pattern ( pattern ) = > {
self . compile_declaration_pattern ( pattern , Opcode ::DefInitLet ) ;
@ -1095,7 +1140,7 @@ impl ByteCompiler {
IterableLoopInitializer ::Const ( declaration ) = > match declaration {
Declaration ::Identifier { ident , .. } = > {
let index = self . get_or_insert_name ( ident . as_ref ( ) ) ;
self . emit ( Opcode ::SetName , & [ index ] ) ;
self . emit ( Opcode ::DefInitConst , & [ index ] ) ;
}
Declaration ::Pattern ( pattern ) = > {
self . compile_declaration_pattern ( pattern , Opcode ::DefInitConst ) ;
@ -1108,11 +1153,11 @@ impl ByteCompiler {
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
self . patch_jump ( exit ) ;
self . pop_loop_control_info ( ) ;
self . emit_opcode ( Opcode ::Pop ) ;
self . emit_opcode ( Opcode ::Pop ) ;
self . emit_opcode ( Opcode ::PushFalse ) ;
self . emit_opcode ( Opcode ::IteratorClose ) ;
self . patch_jump ( exit ) ;
self . patch_jump ( early_exit ) ;
}
Node ::ForOfLoop ( for_of_loop ) = > {
@ -1120,7 +1165,10 @@ impl ByteCompiler {
self . emit_opcode ( Opcode ::InitIterator ) ;
let start_address = self . next_opcode_location ( ) ;
self . push_loop_control_info ( for_of_loop . label ( ) . map ( Into ::into ) , start_address ) ;
self . push_loop_control_info_for_of_in_loop (
for_of_loop . label ( ) . map ( Into ::into ) ,
start_address ,
) ;
self . emit_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
let exit = self . jump_with_custom_opcode ( Opcode ::ForInLoopNext ) ;
@ -1133,7 +1181,7 @@ impl ByteCompiler {
IterableLoopInitializer ::Var ( declaration ) = > match declaration {
Declaration ::Identifier { ident , .. } = > {
let index = self . get_or_insert_name ( ident . as_ref ( ) ) ;
self . emit ( Opcode ::SetName , & [ index ] ) ;
self . emit ( Opcode ::DefInitVar , & [ index ] ) ;
}
Declaration ::Pattern ( pattern ) = > {
self . compile_declaration_pattern ( pattern , Opcode ::DefInitVar ) ;
@ -1142,7 +1190,7 @@ impl ByteCompiler {
IterableLoopInitializer ::Let ( declaration ) = > match declaration {
Declaration ::Identifier { ident , .. } = > {
let index = self . get_or_insert_name ( ident . as_ref ( ) ) ;
self . emit ( Opcode ::SetName , & [ index ] ) ;
self . emit ( Opcode ::DefInitLet , & [ index ] ) ;
}
Declaration ::Pattern ( pattern ) = > {
self . compile_declaration_pattern ( pattern , Opcode ::DefInitLet ) ;
@ -1151,7 +1199,7 @@ impl ByteCompiler {
IterableLoopInitializer ::Const ( declaration ) = > match declaration {
Declaration ::Identifier { ident , .. } = > {
let index = self . get_or_insert_name ( ident . as_ref ( ) ) ;
self . emit ( Opcode ::SetName , & [ index ] ) ;
self . emit ( Opcode ::DefInitConst , & [ index ] ) ;
}
Declaration ::Pattern ( pattern ) = > {
self . compile_declaration_pattern ( pattern , Opcode ::DefInitConst ) ;
@ -1165,8 +1213,9 @@ impl ByteCompiler {
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
self . patch_jump ( exit ) ;
self . pop_loop_control_info ( ) ;
self . emit_opcode ( Opcode ::PushFalse ) ;
self . emit_opcode ( Opcode ::IteratorClose ) ;
}
Node ::WhileLoop ( while_ ) = > {
let start_address = self . next_opcode_location ( ) ;
@ -1200,23 +1249,58 @@ impl ByteCompiler {
self . patch_jump ( exit ) ;
}
Node ::Continue ( node ) = > {
if let Some ( start_address ) = self
. jump_info
. last ( )
. filter ( | info | info . kind = = JumpControlInfoKind ::Try )
. map ( | info | info . start_address )
{
self . emit_opcode ( Opcode ::TryEnd ) ;
self . emit ( Opcode ::FinallySetJump , & [ start_address ] ) ;
let label = self . jump ( ) ;
self . jump_info . last_mut ( ) . unwrap ( ) . try_continues . push ( label ) ;
} else {
let mut items = self
. jump_info
. iter_mut ( )
. iter ( )
. rev ( )
. filter ( | info | info . kind = = JumpControlInfoKind ::Loop ) ;
let target = if node . label ( ) . is_none ( ) {
items . next ( )
let address = if node . label ( ) . is_none ( ) {
items . next ( ) . expect ( "continue target" ) . start_address
} else {
items . find ( | info | info . label . as_deref ( ) = = node . label ( ) )
let mut emit_for_of_in_exit = 0 ;
let mut address_info = None ;
for info in items {
if info . label . as_deref ( ) = = node . label ( ) {
address_info = Some ( info ) ;
break ;
}
if info . for_of_in_loop {
emit_for_of_in_exit + = 1 ;
}
}
let address = address_info . expect ( "continue target" ) . start_address ;
for _ in 0 .. emit_for_of_in_exit {
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::Pop ) ;
self . emit_opcode ( Opcode ::Pop ) ;
}
address
} ;
self . emit ( Opcode ::Jump , & [ address ] ) ;
}
. expect ( "continue target" )
. start_address ;
self . patch_jump_with_target ( label , target ) ;
}
Node ::Break ( node ) = > {
if self
. jump_info
. last ( )
. filter ( | info | info . kind = = JumpControlInfoKind ::Try )
. is_some ( )
{
self . emit_opcode ( Opcode ::TryEnd ) ;
self . emit ( Opcode ::FinallySetJump , & [ u32 ::MAX ] ) ;
}
let label = self . jump ( ) ;
if node . label ( ) . is_none ( ) {
self . jump_info . last_mut ( ) . unwrap ( ) . breaks . push ( label ) ;
@ -1232,7 +1316,7 @@ impl ByteCompiler {
Node ::Block ( block ) = > {
self . emit_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
for node in block . items ( ) {
self . compile_stmt ( node , false ) ;
self . compile_stmt ( node , use_expr ) ;
}
self . emit_opcode ( Opcode ::PopEnvironment ) ;
}
@ -1279,19 +1363,24 @@ impl ByteCompiler {
Node ::Try ( t ) = > {
self . push_try_control_info ( ) ;
let try_start = self . jump_with_custom_opcode ( Opcode ::TryStart ) ;
let try_start = self . next_opcode_location ( ) ;
self . emit ( Opcode ::TryStart , & [ Self ::DUMMY_ADDRESS , 0 ] ) ;
self . emit_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
for node in t . block ( ) . items ( ) {
self . compile_stmt ( node , false ) ;
}
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::TryEnd ) ;
let finally = self . jump ( ) ;
self . patch_jump ( Label { index : try_start } ) ;
self . patch_jump ( try_start ) ;
if let Some ( catch ) = t . catch ( ) {
let catch_start = if t . finally ( ) . is_some ( ) {
Some ( self . jump_with_custom_opcode ( Opcode ::CatchStart ) )
} else {
None
} ;
self . emit_opcode ( Opcode ::PushDeclarativeEnvironment ) ;
if let Some ( decl ) = catch . parameter ( ) {
match decl {
@ -1300,28 +1389,35 @@ impl ByteCompiler {
self . emit ( Opcode ::DefInitLet , & [ index ] ) ;
}
Declaration ::Pattern ( pattern ) = > {
let idents = pattern . idents ( ) ;
for ( i , ident ) in idents . iter ( ) . enumerate ( ) {
if i < idents . len ( ) {
self . emit_opcode ( Opcode ::Dup ) ;
}
let index = self . get_or_insert_name ( ident ) ;
self . emit ( Opcode ::DefInitLet , & [ index ] ) ;
}
self . compile_declaration_pattern ( pattern , Opcode ::DefInitLet ) ;
}
}
} else {
self . emit_opcode ( Opcode ::Pop ) ;
}
for node in catch . block ( ) . items ( ) {
self . compile_stmt ( node , false ) ;
self . compile_stmt ( node , use_expr ) ;
}
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::TryEnd ) ;
if let Some ( catch_start ) = catch_start {
self . emit_opcode ( Opcode ::CatchEnd ) ;
self . patch_jump ( catch_start ) ;
} else {
self . emit_opcode ( Opcode ::CatchEnd2 ) ;
}
}
self . patch_jump ( finally ) ;
if let Some ( finally ) = t . finally ( ) {
self . emit_opcode ( Opcode ::FinallyStart ) ;
let finally_start_address = self . next_opcode_location ( ) ;
self . patch_jump_with_target (
Label {
index : try_start + 4 ,
} ,
finally_start_address ,
) ;
for node in finally . items ( ) {
self . compile_stmt ( node , false ) ;
@ -1379,8 +1475,9 @@ impl ByteCompiler {
_ = > unreachable! ( ) ,
} ;
let strict = body . strict ( ) | | self . code_block . strict ;
let length = parameters . len ( ) as u32 ;
let mut code = CodeBlock ::new ( name . unwrap_or ( "" ) . into ( ) , length , false , true ) ;
let mut code = CodeBlock ::new ( name . unwrap_or ( "" ) . into ( ) , length , strict , true ) ;
if let FunctionKind ::Arrow = kind {
code . constructor = false ;
@ -1391,11 +1488,43 @@ impl ByteCompiler {
code_block : code ,
literals_map : HashMap ::new ( ) ,
names_map : HashMap ::new ( ) ,
functions_map : HashMap ::new ( ) ,
jump_info : Vec ::new ( ) ,
top_level : false ,
} ;
let mut has_rest_parameter = false ;
let mut has_parameter_expressions = false ;
for parameter in parameters {
has_parameter_expressions = has_parameter_expressions | | parameter . init ( ) . is_some ( ) ;
if parameter . is_rest_param ( ) {
has_rest_parameter = true ;
compiler . emit_opcode ( Opcode ::RestParameterInit ) ;
}
match parameter . declaration ( ) {
Declaration ::Identifier { ident , .. } = > {
let index = compiler . get_or_insert_name ( ident . as_ref ( ) ) ;
if let Some ( init ) = parameter . declaration ( ) . init ( ) {
let skip = compiler . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
compiler . compile_expr ( init , true ) ;
compiler . patch_jump ( skip ) ;
}
compiler . emit ( Opcode ::DefInitArg , & [ index ] ) ;
}
Declaration ::Pattern ( pattern ) = > {
compiler . compile_declaration_pattern ( pattern , Opcode ::DefInitArg ) ;
}
}
}
if ! has_rest_parameter {
compiler . emit_opcode ( Opcode ::RestParameterPop ) ;
}
if has_parameter_expressions {
compiler . emit_opcode ( Opcode ::PushFunctionEnvironment )
}
for node in body . items ( ) {
compiler . compile_stmt ( node , false ) ;
}
@ -1416,8 +1545,7 @@ impl ByteCompiler {
match kind {
FunctionKind ::Declaration = > {
let index = self . get_or_insert_name ( name . unwrap ( ) ) ;
let access = Access ::Variable { index } ;
self . access_set ( access , None , false ) ;
self . emit ( Opcode ::DefInitVar , & [ index ] ) ;
}
FunctionKind ::Expression | FunctionKind ::Arrow = > {
if ! use_expr {
@ -1463,7 +1591,7 @@ impl ByteCompiler {
}
}
for arg in call . args ( ) . iter ( ) . rev ( ) {
for arg in call . args ( ) . iter ( ) {
self . compile_expr ( arg , true ) ;
}
@ -1523,7 +1651,6 @@ impl ByteCompiler {
if let Some ( init ) = default_init {
let skip = self . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
self . emit_opcode ( Opcode ::Pop ) ;
self . compile_expr ( init , true ) ;
self . patch_jump ( skip ) ;
}
@ -1559,11 +1686,8 @@ impl ByteCompiler {
if let Some ( init ) = default_init {
let skip = self . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
self . emit_opcode ( Opcode ::Pop ) ;
self . compile_expr ( init , true ) ;
self . patch_jump ( skip ) ;
} else {
self . emit_opcode ( Opcode ::PushUndefined ) ;
}
self . compile_declaration_pattern ( pattern , def ) ;
@ -1584,15 +1708,23 @@ impl ByteCompiler {
self . emit_opcode ( Opcode ::ValueNotNullOrUndefined ) ;
self . emit_opcode ( Opcode ::InitIterator ) ;
for binding in pattern . bindings ( ) {
for ( i , binding ) in pattern . bindings ( ) . iter ( ) . enumerate ( ) {
use BindingPatternTypeArray ::* ;
let next = if i = = pattern . bindings ( ) . len ( ) - 1 {
Opcode ::IteratorNextFull
} else {
Opcode ::IteratorNext
} ;
match binding {
// ArrayBindingPattern : [ ]
Empty = > { }
Empty = > {
self . emit_opcode ( Opcode ::PushFalse ) ;
}
// ArrayBindingPattern : [ Elision ]
Elision = > {
self . emit_opcode ( Opcode ::IteratorNext ) ;
self . emit_opcode ( n ext) ;
self . emit_opcode ( Opcode ::Pop ) ;
}
// SingleNameBinding : BindingIdentifier Initializer[opt]
@ -1600,10 +1732,9 @@ impl ByteCompiler {
ident ,
default_init ,
} = > {
self . emit_opcode ( Opcode ::IteratorN ext) ;
self . emit_opcode ( n ext) ;
if let Some ( init ) = default_init {
let skip = self . jump_with_custom_opcode ( Opcode ::JumpIfNotUndefined ) ;
self . emit_opcode ( Opcode ::Pop ) ;
self . compile_expr ( init , true ) ;
self . patch_jump ( skip ) ;
}
@ -1613,7 +1744,7 @@ impl ByteCompiler {
}
// BindingElement : BindingPattern Initializer[opt]
BindingPattern { pattern } = > {
self . emit_opcode ( Opcode ::IteratorN ext) ;
self . emit_opcode ( n ext) ;
self . compile_declaration_pattern ( pattern , def )
}
// BindingRestElement : ... BindingIdentifier
@ -1622,16 +1753,22 @@ impl ByteCompiler {
let index = self . get_or_insert_name ( ident ) ;
self . emit ( def , & [ index ] ) ;
self . emit_opcode ( Opcode ::PushTrue ) ;
}
// BindingRestElement : ... BindingPattern
BindingPatternRest { pattern } = > {
self . emit_opcode ( Opcode ::IteratorToArray ) ;
self . compile_declaration_pattern ( pattern , def ) ;
self . emit_opcode ( Opcode ::PushTrue ) ;
}
}
}
self . emit_opcode ( Opcode ::Pop ) ;
if pattern . bindings ( ) . is_empty ( ) {
self . emit_opcode ( Opcode ::PushFalse ) ;
}
self . emit_opcode ( Opcode ::IteratorClose ) ;
}
}
}