Browse Source

Skip environment creation when possible for arrow functions

reduce-environment-allocations
raskad 2 months ago
parent
commit
27ab91af56
No known key found for this signature in database
  1. 7
      core/ast/src/expression/literal/object.rs
  2. 7
      core/ast/src/function/arrow_function.rs
  3. 7
      core/ast/src/function/async_arrow_function.rs
  4. 14
      core/ast/src/function/async_function.rs
  5. 14
      core/ast/src/function/async_generator.rs
  6. 7
      core/ast/src/function/class.rs
  7. 14
      core/ast/src/function/generator.rs
  8. 14
      core/ast/src/function/ordinary_function.rs
  9. 78
      core/ast/src/scope_analyzer.rs
  10. 11
      core/engine/src/builtins/function/mod.rs
  11. 7
      core/engine/src/bytecompiler/class.rs
  12. 156
      core/engine/src/bytecompiler/declarations.rs
  13. 12
      core/engine/src/bytecompiler/function.rs
  14. 16
      core/engine/src/bytecompiler/mod.rs
  15. 10
      core/engine/src/vm/code_block.rs

7
core/ast/src/expression/literal/object.rs

@ -469,6 +469,13 @@ impl ObjectMethodDefinition {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the object method definition contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for ObjectMethodDefinition {

7
core/ast/src/function/arrow_function.rs

@ -86,6 +86,13 @@ impl ArrowFunction {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the arrow function contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for ArrowFunction {

7
core/ast/src/function/async_arrow_function.rs

@ -86,6 +86,13 @@ impl AsyncArrowFunction {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the function declaration contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for AsyncArrowFunction {

14
core/ast/src/function/async_function.rs

@ -78,6 +78,13 @@ impl AsyncFunctionDeclaration {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the async function declaration contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for AsyncFunctionDeclaration {
@ -207,6 +214,13 @@ impl AsyncFunctionExpression {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the async function expression contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for AsyncFunctionExpression {

14
core/ast/src/function/async_generator.rs

@ -77,6 +77,13 @@ impl AsyncGeneratorDeclaration {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the async generator declaration contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for AsyncGeneratorDeclaration {
@ -206,6 +213,13 @@ impl AsyncGeneratorExpression {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the async generator expression contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for AsyncGeneratorExpression {

7
core/ast/src/function/class.rs

@ -748,6 +748,13 @@ impl ClassMethodDefinition {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the class method definition contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for ClassMethodDefinition {

14
core/ast/src/function/generator.rs

@ -76,6 +76,13 @@ impl GeneratorDeclaration {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the generator declaration contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for GeneratorDeclaration {
@ -205,6 +212,13 @@ impl GeneratorExpression {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the generator expression contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for GeneratorExpression {

14
core/ast/src/function/ordinary_function.rs

@ -77,6 +77,13 @@ impl FunctionDeclaration {
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
/// Returns `true` if the function declaration contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
}
impl ToIndentedString for FunctionDeclaration {
@ -207,6 +214,13 @@ impl FunctionExpression {
&self.scopes
}
/// Returns `true` if the function expression contains a direct call to `eval`.
#[inline]
#[must_use]
pub const fn contains_direct_eval(&self) -> bool {
self.contains_direct_eval
}
/// Analyze the scope of the function expression.
pub fn analyze_scope(&mut self, strict: bool, scope: &Scope, interner: &Interner) -> bool {
if !collect_bindings(self, strict, false, scope, interner) {

78
core/ast/src/scope_analyzer.rs

@ -16,8 +16,9 @@ use crate::{
FunctionExpression, GeneratorDeclaration, GeneratorExpression,
},
operations::{
bound_names, lexically_declared_names, lexically_scoped_declarations, var_declared_names,
var_scoped_declarations, LexicallyScopedDeclaration, VarScopedDeclaration,
bound_names, contains, lexically_declared_names, lexically_scoped_declarations,
var_declared_names, var_scoped_declarations, ContainsSymbol, LexicallyScopedDeclaration,
VarScopedDeclaration,
},
property::PropertyName,
scope::{FunctionScopes, IdentifierReference, Scope},
@ -1171,11 +1172,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut FunctionDeclaration,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut None,
false,
contains_direct_eval,
)
}
@ -1183,11 +1187,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut GeneratorDeclaration,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut None,
false,
contains_direct_eval,
)
}
@ -1195,11 +1202,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut AsyncFunctionDeclaration,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut None,
false,
contains_direct_eval,
)
}
@ -1207,11 +1217,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut AsyncGeneratorDeclaration,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut None,
false,
contains_direct_eval,
)
}
@ -1219,11 +1232,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut FunctionExpression,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut node.name_scope,
false,
contains_direct_eval,
)
}
@ -1231,11 +1247,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut GeneratorExpression,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut node.name_scope,
false,
contains_direct_eval,
)
}
@ -1243,11 +1262,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut AsyncFunctionExpression,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut node.name_scope,
false,
contains_direct_eval,
)
}
@ -1255,11 +1277,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut AsyncGeneratorExpression,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut node.name_scope,
false,
contains_direct_eval,
)
}
@ -1267,11 +1292,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut ArrowFunction,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut None,
true,
contains_direct_eval,
)
}
@ -1279,11 +1307,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
&mut self,
node: &'ast mut AsyncArrowFunction,
) -> ControlFlow<Self::BreakTy> {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut None,
true,
contains_direct_eval,
)
}
@ -1338,12 +1369,17 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
node: &'ast mut ClassElement,
) -> ControlFlow<Self::BreakTy> {
match node {
ClassElement::MethodDefinition(node) => self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut None,
),
ClassElement::MethodDefinition(node) => {
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut None,
false,
contains_direct_eval,
)
}
ClassElement::FieldDefinition(field) | ClassElement::StaticFieldDefinition(field) => {
try_break!(self.visit_property_name_mut(&mut field.name));
let index = self.index;
@ -1371,12 +1407,17 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
}
ControlFlow::Continue(())
}
ClassElement::StaticBlock(node) => self.visit_function_like(
&mut node.body,
&mut FormalParameterList::default(),
&mut node.scopes,
&mut None,
),
ClassElement::StaticBlock(node) => {
let contains_direct_eval = contains(node.statements(), ContainsSymbol::DirectEval);
self.visit_function_like(
&mut node.body,
&mut FormalParameterList::default(),
&mut node.scopes,
&mut None,
false,
contains_direct_eval,
)
}
}
}
@ -1390,11 +1431,14 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
try_break!(self.visit_expression_mut(name));
}
}
let contains_direct_eval = node.contains_direct_eval();
self.visit_function_like(
&mut node.body,
&mut node.parameters,
&mut node.scopes,
&mut None,
false,
contains_direct_eval,
)
}
@ -1531,6 +1575,8 @@ impl ScopeIndexVisitor {
parameters: &mut FormalParameterList,
scopes: &mut FunctionScopes,
name_scope: &mut Option<Scope>,
arrow: bool,
contains_direct_eval: bool,
) -> ControlFlow<()> {
let index = self.index;
if let Some(scope) = name_scope {
@ -1539,7 +1585,9 @@ impl ScopeIndexVisitor {
}
scope.set_index(self.index);
}
self.index += 1;
if !(arrow && scopes.function_scope.all_bindings_local() && !contains_direct_eval) {
self.index += 1;
}
scopes.function_scope.set_index(self.index);
if let Some(scope) = &scopes.parameters_eval_scope {
if !scope.all_bindings_local() {

11
core/engine/src/builtins/function/mod.rs

@ -655,6 +655,7 @@ impl BuiltInFunctionObject {
context.realm().scope().clone(),
context.realm().scope().clone(),
function.scopes(),
function.contains_direct_eval(),
context.interner_mut(),
);
@ -1026,10 +1027,12 @@ pub(crate) fn function_call(
last_env += 1;
}
context.vm.environments.push_function(
code.constant_scope(last_env),
FunctionSlots::new(this, function_object.clone(), None),
);
if code.has_function_scope() {
context.vm.environments.push_function(
code.constant_scope(last_env),
FunctionSlots::new(this, function_object.clone(), None),
);
}
Ok(CallValue::Ready)
}

7
core/engine/src/bytecompiler/class.rs

@ -96,6 +96,7 @@ impl ByteCompiler<'_> {
compiler.code_block_flags |= CodeBlockFlags::IS_CLASS_CONSTRUCTOR;
if let Some(expr) = &class.constructor {
compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE;
let _ = compiler.push_scope(expr.scopes().function_scope());
compiler.length = expr.parameters().length();
@ -115,11 +116,13 @@ impl ByteCompiler<'_> {
compiler.emit_opcode(Opcode::PushUndefined);
} else if class.super_ref.is_some() {
// We push an empty, unused function scope since the compiler expects a function scope.
compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE;
let _ = compiler.push_scope(&Scope::new(compiler.lexical_scope.clone(), true));
compiler.emit_opcode(Opcode::SuperCallDerived);
compiler.emit_opcode(Opcode::BindThisValue);
} else {
// We push an empty, unused function scope since the compiler expects a function scope.
compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE;
let _ = compiler.push_scope(&Scope::new(compiler.lexical_scope.clone(), true));
compiler.emit_opcode(Opcode::PushUndefined);
}
@ -288,6 +291,7 @@ impl ByteCompiler<'_> {
);
// Function environment
field_compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE;
let _ = field_compiler.push_scope(field.scope());
let is_anonymous_function = if let Some(node) = &field.field() {
field_compiler.compile_expr(node, true);
@ -322,6 +326,7 @@ impl ByteCompiler<'_> {
self.interner,
self.in_with,
);
field_compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE;
let _ = field_compiler.push_scope(field.scope());
if let Some(node) = field.field() {
field_compiler.compile_expr(node, true);
@ -363,6 +368,7 @@ impl ByteCompiler<'_> {
self.interner,
self.in_with,
);
field_compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE;
let _ = field_compiler.push_scope(field.scope());
let is_anonymous_function = if let Some(node) = &field.field() {
field_compiler.compile_expr(node, true);
@ -406,6 +412,7 @@ impl ByteCompiler<'_> {
self.interner,
self.in_with,
);
compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE;
let _ = compiler.push_scope(block.scopes().function_scope());
compiler.function_declaration_instantiation(

156
core/engine/src/bytecompiler/declarations.rs

@ -479,41 +479,46 @@ impl ByteCompiler<'_> {
// 16. For each Parse Node f of functionsToInitialize, do
for function in functions_to_initialize {
// a. Let fn be the sole element of the BoundNames of f.
let (name, generator, r#async, parameters, body, scopes) = match &function {
VarScopedDeclaration::FunctionDeclaration(f) => (
f.name(),
false,
false,
f.parameters(),
f.body(),
f.scopes().clone(),
),
VarScopedDeclaration::GeneratorDeclaration(f) => (
f.name(),
true,
false,
f.parameters(),
f.body(),
f.scopes().clone(),
),
VarScopedDeclaration::AsyncFunctionDeclaration(f) => (
f.name(),
false,
true,
f.parameters(),
f.body(),
f.scopes().clone(),
),
VarScopedDeclaration::AsyncGeneratorDeclaration(f) => (
f.name(),
true,
true,
f.parameters(),
f.body(),
f.scopes().clone(),
),
VarScopedDeclaration::VariableDeclaration(_) => continue,
};
let (name, generator, r#async, parameters, body, scopes, contains_direct_eval) =
match &function {
VarScopedDeclaration::FunctionDeclaration(f) => (
f.name(),
false,
false,
f.parameters(),
f.body(),
f.scopes().clone(),
f.contains_direct_eval(),
),
VarScopedDeclaration::GeneratorDeclaration(f) => (
f.name(),
true,
false,
f.parameters(),
f.body(),
f.scopes().clone(),
f.contains_direct_eval(),
),
VarScopedDeclaration::AsyncFunctionDeclaration(f) => (
f.name(),
false,
true,
f.parameters(),
f.body(),
f.scopes().clone(),
f.contains_direct_eval(),
),
VarScopedDeclaration::AsyncGeneratorDeclaration(f) => (
f.name(),
true,
true,
f.parameters(),
f.body(),
f.scopes().clone(),
f.contains_direct_eval(),
),
VarScopedDeclaration::VariableDeclaration(_) => continue,
};
let code = FunctionCompiler::new()
.name(name.sym().to_js_string(self.interner()))
@ -527,6 +532,7 @@ impl ByteCompiler<'_> {
self.variable_scope.clone(),
self.lexical_scope.clone(),
&scopes,
contains_direct_eval,
self.interner,
);
@ -737,43 +743,48 @@ impl ByteCompiler<'_> {
// 17. For each Parse Node f of functionsToInitialize, do
for function in functions_to_initialize {
// a. Let fn be the sole element of the BoundNames of f.
let (name, generator, r#async, parameters, body, scopes) = match &function {
VarScopedDeclaration::FunctionDeclaration(f) => (
f.name(),
false,
false,
f.parameters(),
f.body(),
f.scopes().clone(),
),
VarScopedDeclaration::GeneratorDeclaration(f) => (
f.name(),
true,
false,
f.parameters(),
f.body(),
f.scopes().clone(),
),
VarScopedDeclaration::AsyncFunctionDeclaration(f) => (
f.name(),
false,
true,
f.parameters(),
f.body(),
f.scopes().clone(),
),
VarScopedDeclaration::AsyncGeneratorDeclaration(f) => (
f.name(),
true,
true,
f.parameters(),
f.body(),
f.scopes().clone(),
),
VarScopedDeclaration::VariableDeclaration(_) => {
continue;
}
};
let (name, generator, r#async, parameters, body, scopes, contains_direct_eval) =
match &function {
VarScopedDeclaration::FunctionDeclaration(f) => (
f.name(),
false,
false,
f.parameters(),
f.body(),
f.scopes().clone(),
f.contains_direct_eval(),
),
VarScopedDeclaration::GeneratorDeclaration(f) => (
f.name(),
true,
false,
f.parameters(),
f.body(),
f.scopes().clone(),
f.contains_direct_eval(),
),
VarScopedDeclaration::AsyncFunctionDeclaration(f) => (
f.name(),
false,
true,
f.parameters(),
f.body(),
f.scopes().clone(),
f.contains_direct_eval(),
),
VarScopedDeclaration::AsyncGeneratorDeclaration(f) => (
f.name(),
true,
true,
f.parameters(),
f.body(),
f.scopes().clone(),
f.contains_direct_eval(),
),
VarScopedDeclaration::VariableDeclaration(_) => {
continue;
}
};
let code = FunctionCompiler::new()
.name(name.sym().to_js_string(self.interner()))
@ -788,6 +799,7 @@ impl ByteCompiler<'_> {
self.variable_scope.clone(),
self.lexical_scope.clone(),
&scopes,
contains_direct_eval,
self.interner,
);

12
core/engine/src/bytecompiler/function.rs

@ -94,6 +94,7 @@ impl FunctionCompiler {
}
/// Compile a function statement list and it's parameters into bytecode.
#[allow(clippy::too_many_arguments)]
pub(crate) fn compile(
mut self,
parameters: &FormalParameterList,
@ -101,6 +102,7 @@ impl FunctionCompiler {
variable_environment: Scope,
lexical_environment: Scope,
scopes: &FunctionScopes,
contains_direct_eval: bool,
interner: &mut Interner,
) -> Gc<CodeBlock> {
self.strict = self.strict || body.strict();
@ -134,8 +136,14 @@ impl FunctionCompiler {
let _ = compiler.push_scope(&scope);
}
}
// Function environment
let _ = compiler.push_scope(scopes.function_scope());
if self.arrow && scopes.function_scope().all_bindings_local() && !contains_direct_eval {
compiler.variable_scope = scopes.function_scope().clone();
compiler.lexical_scope = scopes.function_scope().clone();
} else {
compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE;
let _ = compiler.push_scope(scopes.function_scope());
}
// Taken from:
// - 15.9.3 Runtime Semantics: EvaluateAsyncConciseBody: <https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncconcisebody>

16
core/engine/src/bytecompiler/mod.rs

@ -122,6 +122,7 @@ pub(crate) struct FunctionSpec<'a> {
body: &'a FunctionBody,
pub(crate) scopes: &'a FunctionScopes,
pub(crate) name_scope: Option<&'a Scope>,
pub(crate) contains_direct_eval: bool,
}
impl<'a> From<&'a FunctionDeclaration> for FunctionSpec<'a> {
@ -133,6 +134,7 @@ impl<'a> From<&'a FunctionDeclaration> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: None,
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -146,6 +148,7 @@ impl<'a> From<&'a GeneratorDeclaration> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: None,
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -159,6 +162,7 @@ impl<'a> From<&'a AsyncFunctionDeclaration> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: None,
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -172,6 +176,7 @@ impl<'a> From<&'a AsyncGeneratorDeclaration> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: None,
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -185,6 +190,7 @@ impl<'a> From<&'a FunctionExpression> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: function.name_scope(),
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -198,6 +204,7 @@ impl<'a> From<&'a ArrowFunction> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: None,
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -211,6 +218,7 @@ impl<'a> From<&'a AsyncArrowFunction> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: None,
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -224,6 +232,7 @@ impl<'a> From<&'a AsyncFunctionExpression> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: function.name_scope(),
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -237,6 +246,7 @@ impl<'a> From<&'a GeneratorExpression> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: function.name_scope(),
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -250,6 +260,7 @@ impl<'a> From<&'a AsyncGeneratorExpression> for FunctionSpec<'a> {
body: function.body(),
scopes: function.scopes(),
name_scope: function.name_scope(),
contains_direct_eval: function.contains_direct_eval(),
}
}
}
@ -270,6 +281,7 @@ impl<'a> From<&'a ClassMethodDefinition> for FunctionSpec<'a> {
body: method.body(),
scopes: method.scopes(),
name_scope: None,
contains_direct_eval: method.contains_direct_eval(),
}
}
}
@ -290,6 +302,7 @@ impl<'a> From<&'a ObjectMethodDefinition> for FunctionSpec<'a> {
body: method.body(),
scopes: method.scopes(),
name_scope: None,
contains_direct_eval: method.contains_direct_eval(),
}
}
}
@ -1518,6 +1531,7 @@ impl<'ctx> ByteCompiler<'ctx> {
self.variable_scope.clone(),
self.lexical_scope.clone(),
scopes,
function.contains_direct_eval,
self.interner,
);
@ -1595,6 +1609,7 @@ impl<'ctx> ByteCompiler<'ctx> {
self.variable_scope.clone(),
self.lexical_scope.clone(),
scopes,
function.contains_direct_eval,
self.interner,
);
@ -1638,6 +1653,7 @@ impl<'ctx> ByteCompiler<'ctx> {
self.variable_scope.clone(),
self.lexical_scope.clone(),
scopes,
function.contains_direct_eval,
self.interner,
);

10
core/engine/src/vm/code_block.rs

@ -66,6 +66,9 @@ bitflags! {
/// Arrow and method functions don't have `"prototype"` property.
const HAS_PROTOTYPE_PROPERTY = 0b1000_0000;
/// If the function requires a function scope.
const HAS_FUNCTION_SCOPE = 0b1_0000_0000;
/// Trace instruction execution to `stdout`.
#[cfg(feature = "trace")]
const TRACEABLE = 0b1000_0000_0000_0000;
@ -271,6 +274,13 @@ impl CodeBlock {
.contains(CodeBlockFlags::HAS_PROTOTYPE_PROPERTY)
}
/// Returns true if this function requires a function scope.
pub(crate) fn has_function_scope(&self) -> bool {
self.flags
.get()
.contains(CodeBlockFlags::HAS_FUNCTION_SCOPE)
}
/// 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)> {

Loading…
Cancel
Save