@ -3,7 +3,7 @@
//! This module is for the `CodeBlock` which implements a function representation in the VM
use crate ::{
builtins ::function ::{ FunctionKind , OrdinaryFunction , ThisMode } ,
builtins ::function ::{ OrdinaryFunction , ThisMode } ,
environments ::{ BindingLocator , CompileTimeEnvironment } ,
object ::{ JsObject , ObjectData , PROTOTYPE } ,
property ::PropertyDescriptor ,
@ -48,7 +48,7 @@ unsafe impl Readable for f64 {}
bitflags ! {
/// Flags for [`CodeBlock`].
#[ derive(Clone, Copy, Debug, Finalize) ]
pub ( crate ) struct CodeBlockFlags : u8 {
pub ( crate ) struct CodeBlockFlags : u16 {
/// Is this function in strict mode.
const STRICT = 0b0000_0001 ;
@ -72,9 +72,13 @@ bitflags! {
/// `[[ConstructorKind]]`
const IS_DERIVED_CONSTRUCTOR = 0b0100_0000 ;
const IS_ASYNC = 0b1000_0000 ;
const IS_GENERATOR = 0b0001_0000_0000 ;
const IS_ARROW = 0b0010_0000_0000 ;
/// Trace instruction execution to `stdout`.
#[ cfg(feature = " trace " ) ]
const TRACEABLE = 0b1000_0000 ;
const TRACEABLE = 0b1000_0000_0000_0000 ;
}
}
@ -251,6 +255,26 @@ impl CodeBlock {
. contains ( CodeBlockFlags ::IS_DERIVED_CONSTRUCTOR )
}
/// Returns true if this function an async function.
pub ( crate ) fn is_async ( & self ) -> bool {
self . flags . get ( ) . contains ( CodeBlockFlags ::IS_ASYNC )
}
/// Returns true if this function an generator function.
pub ( crate ) fn is_generator ( & self ) -> bool {
self . flags . get ( ) . contains ( CodeBlockFlags ::IS_GENERATOR )
}
/// Returns true if this function an async function.
pub ( crate ) fn is_ordinary ( & self ) -> bool {
! self . is_async ( ) & & ! self . is_generator ( )
}
/// Returns true if this function an arrow function.
pub ( crate ) fn is_arrow ( & self ) -> bool {
self . flags . get ( ) . contains ( CodeBlockFlags ::IS_ARROW )
}
/// Find exception [`Handler`] in the code block given the current program counter (`pc`).
#[ inline ]
pub ( crate ) fn find_handler ( & self , pc : u32 ) -> Option < ( usize , & Handler ) > {
@ -431,8 +455,7 @@ impl CodeBlock {
Instruction ::TemplateCreate { count , site } = > {
format! ( "{}, {site}" , count . value ( ) )
}
Instruction ::GetFunction { index , method }
| Instruction ::GetFunctionAsync { index , method } = > {
Instruction ::GetFunction { index , method } = > {
let index = index . value ( ) as usize ;
format! (
"{index:04}: '{}' (length: {}), method: {method}" ,
@ -440,10 +463,7 @@ impl CodeBlock {
self . constant_function ( index ) . length
)
}
Instruction ::GetArrowFunction { index }
| Instruction ::GetAsyncArrowFunction { index }
| Instruction ::GetGenerator { index }
| Instruction ::GetGeneratorAsync { index } = > {
Instruction ::GetArrowFunction { index } | Instruction ::GetGenerator { index } = > {
let index = index . value ( ) as usize ;
format! (
"{index:04}: '{}' (length: {})" ,
@ -692,7 +712,10 @@ impl CodeBlock {
| Instruction ::Reserved53
| Instruction ::Reserved54
| Instruction ::Reserved55
| Instruction ::Reserved56 = > unreachable! ( "Reserved opcodes are unrechable" ) ,
| Instruction ::Reserved56
| Instruction ::Reserved57
| Instruction ::Reserved58
| Instruction ::Reserved59 = > unreachable! ( "Reserved opcodes are unrechable" ) ,
}
}
}
@ -821,7 +844,6 @@ impl ToInternedString for CodeBlock {
/// This is slower than direct object template construction that is done in [`create_function_object_fast`].
pub ( crate ) fn create_function_object (
code : Gc < CodeBlock > ,
r#async : bool ,
prototype : JsObject ,
context : & mut Context < ' _ > ,
) -> JsObject {
@ -832,34 +854,19 @@ pub(crate) fn create_function_object(
let script_or_module = context . get_active_script_or_module ( ) ;
let function = if r#async {
OrdinaryFunction {
code ,
environments : context . vm . environments . clone ( ) ,
home_object : None ,
script_or_module ,
kind : FunctionKind ::Async ,
realm : context . realm ( ) . clone ( ) ,
}
} else {
OrdinaryFunction {
code ,
environments : context . vm . environments . clone ( ) ,
home_object : None ,
script_or_module ,
kind : FunctionKind ::Ordinary {
fields : ThinVec ::new ( ) ,
private_methods : ThinVec ::new ( ) ,
} ,
realm : context . realm ( ) . clone ( ) ,
}
} ;
let is_async = code . is_async ( ) ;
let function = OrdinaryFunction ::new (
code ,
context . vm . environments . clone ( ) ,
script_or_module ,
context . realm ( ) . clone ( ) ,
) ;
let data = ObjectData ::ordinary_function ( function , ! r# async) ;
let data = ObjectData ::ordinary_function ( function , ! is_async ) ;
let templates = context . intrinsics ( ) . templates ( ) ;
let ( mut template , storage , constructor_prototype ) = if r# async {
let ( mut template , storage , constructor_prototype ) = if is_async {
(
templates . function_without_proto ( ) . clone ( ) ,
vec! [ length , name ] ,
@ -896,8 +903,6 @@ pub(crate) fn create_function_object(
/// with all the properties and prototype set.
pub ( crate ) fn create_function_object_fast (
code : Gc < CodeBlock > ,
r#async : bool ,
arrow : bool ,
method : bool ,
context : & mut Context < ' _ > ,
) -> JsObject {
@ -908,33 +913,24 @@ pub(crate) fn create_function_object_fast(
let script_or_module = context . get_active_script_or_module ( ) ;
let kind = if r#async {
FunctionKind ::Async
} else {
FunctionKind ::Ordinary {
fields : ThinVec ::new ( ) ,
private_methods : ThinVec ::new ( ) ,
}
} ;
let function = OrdinaryFunction {
let is_async = code . is_async ( ) ;
let is_arrow = code . is_arrow ( ) ;
let function = OrdinaryFunction ::new (
code ,
environments : context . vm . environments . clone ( ) ,
context . vm . environments . clone ( ) ,
script_or_module ,
home_object : None ,
kind ,
realm : context . realm ( ) . clone ( ) ,
} ;
context . realm ( ) . clone ( ) ,
) ;
let data = ObjectData ::ordinary_function ( function , ! method & & ! arrow & & ! r# async) ;
let data = ObjectData ::ordinary_function ( function , ! method & & ! is_arrow & & ! is_async ) ;
if r# async {
if is_ async {
context
. intrinsics ( )
. templates ( )
. async_function ( )
. create ( data , vec! [ length , name ] )
} else if arrow | | method {
} else if is_ arrow | | method {
context
. intrinsics ( )
. templates ( )
@ -962,13 +958,13 @@ pub(crate) fn create_function_object_fast(
/// Creates a new generator function object.
pub ( crate ) fn create_generator_function_object (
code : Gc < CodeBlock > ,
r#async : bool ,
prototype : Option < JsObject > ,
context : & mut Context < ' _ > ,
) -> JsObject {
let is_async = code . is_async ( ) ;
let function_prototype = if let Some ( prototype ) = prototype {
prototype
} else if r# async {
} else if is_ async {
context
. intrinsics ( )
. constructors ( )
@ -998,7 +994,7 @@ pub(crate) fn create_generator_function_object(
let prototype = JsObject ::from_proto_and_data_with_shared_shape (
context . root_shape ( ) ,
if r# async {
if is_ async {
context . intrinsics ( ) . objects ( ) . async_generator ( )
} else {
context . intrinsics ( ) . objects ( ) . generator ( )
@ -1008,29 +1004,25 @@ pub(crate) fn create_generator_function_object(
let script_or_module = context . get_active_script_or_module ( ) ;
let constructor = if r# async {
let function = OrdinaryFunction {
let constructor = if is_ async {
let function = OrdinaryFunction ::new (
code ,
environments : context . vm . environments . clone ( ) ,
home_object : None ,
context . vm . environments . clone ( ) ,
script_or_module ,
kind : FunctionKind ::AsyncGenerator ,
realm : context . realm ( ) . clone ( ) ,
} ;
context . realm ( ) . clone ( ) ,
) ;
JsObject ::from_proto_and_data_with_shared_shape (
context . root_shape ( ) ,
function_prototype ,
ObjectData ::async_generator_function ( function ) ,
)
} else {
let function = OrdinaryFunction {
let function = OrdinaryFunction ::new (
code ,
environments : context . vm . environments . clone ( ) ,
home_object : None ,
context . vm . environments . clone ( ) ,
script_or_module ,
kind : FunctionKind ::Generator ,
realm : context . realm ( ) . clone ( ) ,
} ;
context . realm ( ) . clone ( ) ,
) ;
JsObject ::from_proto_and_data_with_shared_shape (
context . root_shape ( ) ,
function_prototype ,