Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 15 additions & 17 deletions core/ast/src/scope_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2284,10 +2284,10 @@ pub struct EvalDeclarationBindings {
pub new_annex_b_function_names: Vec<IdentifierReference>,

/// New function names created during the declaration of an eval ast node.
pub new_function_names: FxHashMap<Identifier, (IdentifierReference, bool)>,
pub new_function_names: FxHashMap<Identifier, IdentifierReference>,

/// New variable names created during the declaration of an eval ast node.
pub new_var_names: Vec<IdentifierReference>,
/// Variable names declared during the declaration of an eval ast node.
pub declared_var_names: Vec<IdentifierReference>,
}

/// `EvalDeclarationInstantiation ( body, varEnv, lexEnv, privateEnv, strict )`
Expand Down Expand Up @@ -2532,10 +2532,7 @@ pub(crate) fn eval_declaration_instantiation_scope(
let binding = var_env.set_mutable_binding(n).expect("must not fail");
result.new_function_names.insert(
name,
(
IdentifierReference::new(binding.locator(), !var_env.is_function(), true),
true,
),
IdentifierReference::new(binding.locator(), !var_env.is_function(), true),
);
} else {
// 1. NOTE: The following invocation cannot return an abrupt completion because of the validation preceding step 14.
Expand All @@ -2544,10 +2541,7 @@ pub(crate) fn eval_declaration_instantiation_scope(
let binding = var_env.create_mutable_binding(n, !strict);
result.new_function_names.insert(
name,
(
IdentifierReference::new(binding, !var_env.is_function(), true),
false,
),
IdentifierReference::new(binding, !var_env.is_function(), true),
);
}
}
Expand All @@ -2568,13 +2562,17 @@ pub(crate) fn eval_declaration_instantiation_scope(
// 1. NOTE: The following invocation cannot return an abrupt completion because of the validation preceding step 14.
// 2. Perform ! varEnv.CreateMutableBinding(vn, true).
// 3. Perform ! varEnv.InitializeBinding(vn, undefined).
let binding = var_env.create_mutable_binding(name, true);
result.new_var_names.push(IdentifierReference::new(
binding,
!var_env.is_function(),
true,
));
drop(var_env.create_mutable_binding(name.clone(), true));
}

let binding = var_env
.get_binding_reference(&name)
.expect("binding must exist");
result.declared_var_names.push(IdentifierReference::new(
binding.locator(),
!var_env.is_function(),
true,
));
}
}

Expand Down
23 changes: 9 additions & 14 deletions core/engine/src/bytecompiler/declarations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -838,24 +838,19 @@ impl ByteCompiler<'_> {
self.emit_get_function(&dst, index);

// i. Let bindingExists be ! varEnv.HasBinding(fn).
let (binding, binding_exists) = bindings
let binding = bindings
.new_function_names
.get(&name)
.expect("binding must exist");

// ii. If bindingExists is false, then
// 1. NOTE: The following invocation cannot return an abrupt completion because of the validation preceding step 14.
// 2. Perform ! varEnv.CreateMutableBinding(fn, true).
// 3. Perform ! varEnv.InitializeBinding(fn, fo).
// iii. Else,
if *binding_exists {
// 1. Perform ! varEnv.SetMutableBinding(fn, fo, false).
let index = self.insert_binding(binding.clone());
self.emit_binding_access(BindingAccessOpcode::SetName, &index, &dst);
} else {
// 1. NOTE: The following invocation cannot return an abrupt completion because of the validation preceding step 14.
// 2. Perform ! varEnv.CreateMutableBinding(fn, true).
// 3. Perform ! varEnv.InitializeBinding(fn, fo).
let index = self.insert_binding(binding.clone());
self.emit_binding_access(BindingAccessOpcode::DefInitVar, &index, &dst);
}
// 1. Perform ! varEnv.SetMutableBinding(fn, fo, false).
let index = self.insert_binding(binding.clone());
self.emit_binding_access(BindingAccessOpcode::DefInitVar, &index, &dst);
self.register_allocator.dealloc(dst);
}
}
Expand All @@ -872,15 +867,15 @@ impl ByteCompiler<'_> {
}
}
// 18.b
for binding in bindings.new_var_names {
for binding in bindings.declared_var_names {
// i. Let bindingExists be ! varEnv.HasBinding(vn).
// ii. If bindingExists is false, then
// 1. NOTE: The following invocation cannot return an abrupt completion because of the validation preceding step 14.
// 2. Perform ! varEnv.CreateMutableBinding(vn, true).
// 3. Perform ! varEnv.InitializeBinding(vn, undefined).
let index = self.insert_binding(binding);
self.emit_binding_access(
BindingAccessOpcode::DefInitVar,
BindingAccessOpcode::DefEvalVar,
&index,
&CallFrame::undefined_register(),
);
Expand Down
11 changes: 10 additions & 1 deletion core/engine/src/bytecompiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ pub(crate) enum BindingAccessOpcode {
DeleteName,
GetLocator,
DefVar,
DefEvalVar,
}

/// Manages the source position scope, push on creation, pop on drop.
Expand Down Expand Up @@ -918,6 +919,9 @@ impl<'ctx> ByteCompiler<'ctx> {
}
BindingAccessOpcode::GetLocator => self.bytecode.emit_get_locator((*index).into()),
BindingAccessOpcode::DefVar => self.bytecode.emit_def_var((*index).into()),
BindingAccessOpcode::DefEvalVar => {
self.bytecode.emit_def_eval_var((*index).into());
}
BindingAccessOpcode::PutLexicalValue => self
.bytecode
.emit_put_lexical_value(value.variable(), (*index).into()),
Expand All @@ -943,6 +947,9 @@ impl<'ctx> ByteCompiler<'ctx> {
}
BindingAccessOpcode::GetLocator => self.bytecode.emit_get_locator((*index).into()),
BindingAccessOpcode::DefVar => self.bytecode.emit_def_var((*index).into()),
BindingAccessOpcode::DefEvalVar => {
self.bytecode.emit_def_eval_var((*index).into());
}
BindingAccessOpcode::PutLexicalValue => self
.bytecode
.emit_put_lexical_value(value.variable(), (*index).into()),
Expand Down Expand Up @@ -978,7 +985,9 @@ impl<'ctx> ByteCompiler<'ctx> {
| BindingAccessOpcode::GetNameAndLocator => {
self.bytecode.emit_move(value.variable(), (*index).into());
}
BindingAccessOpcode::GetLocator | BindingAccessOpcode::DefVar => {}
BindingAccessOpcode::GetLocator
| BindingAccessOpcode::DefVar
| BindingAccessOpcode::DefEvalVar => {}
BindingAccessOpcode::SetName
| BindingAccessOpcode::DefInitVar
| BindingAccessOpcode::PutLexicalValue
Expand Down
73 changes: 70 additions & 3 deletions core/engine/src/environments/runtime/declarative/function.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use boa_ast::scope::Scope;
use boa_gc::{Finalize, GcRefCell, Trace, custom_trace};
use std::cell::RefCell;

use crate::{JsNativeError, JsObject, JsResult, JsValue, builtins::function::OrdinaryFunction};

#[derive(Debug, Trace, Finalize)]
pub(crate) struct FunctionEnvironment {
bindings: GcRefCell<Vec<Option<JsValue>>>,
#[unsafe_ignore_trace]
deletable_bindings: RefCell<Vec<bool>>,
#[unsafe_ignore_trace]
deleted_bindings: RefCell<Vec<bool>>,
slots: Box<FunctionSlots>,

// Safety: Nothing in `Scope` needs tracing.
Expand All @@ -18,6 +23,8 @@ impl FunctionEnvironment {
pub(crate) fn new(bindings_count: u32, slots: FunctionSlots, scope: Scope) -> Self {
Self {
bindings: GcRefCell::new(vec![None; bindings_count as usize]),
deletable_bindings: RefCell::new(vec![false; bindings_count as usize]),
deleted_bindings: RefCell::new(vec![false; bindings_count as usize]),
slots: Box::new(slots),
scope,
}
Expand Down Expand Up @@ -53,9 +60,69 @@ impl FunctionEnvironment {
self.bindings.borrow_mut()[index as usize] = Some(value);
}

/// Gets the bindings of this poisonable environment.
pub(crate) const fn bindings(&self) -> &GcRefCell<Vec<Option<JsValue>>> {
&self.bindings
pub(crate) fn extend_from_compile(&self) {
let compile_bindings_len = self.scope.num_bindings() as usize;
let mut bindings = self.bindings.borrow_mut();
let bindings_len = bindings.len();

if compile_bindings_len <= bindings_len {
return;
}

bindings.resize(compile_bindings_len, None);

let mut deletable_bindings = self.deletable_bindings.borrow_mut();
deletable_bindings.resize(compile_bindings_len, false);
deletable_bindings[bindings_len..].fill(true);

self.deleted_bindings
.borrow_mut()
.resize(compile_bindings_len, false);
}

pub(crate) fn is_deleted_binding(&self, index: u32) -> bool {
self.deleted_bindings
.borrow()
.get(index as usize)
.copied()
.unwrap_or_default()
}

#[track_caller]
pub(crate) fn restore_deleted_binding(&self, index: u32) {
let index = index as usize;
if let Some(deleted) = self.deleted_bindings.borrow_mut().get_mut(index) {
*deleted = false;
}
}

#[track_caller]
pub(crate) fn delete_binding(&self, index: u32) -> bool {
let index = index as usize;

if self
.deleted_bindings
.borrow()
.get(index)
.copied()
.unwrap_or_default()
{
return true;
}

if !self
.deletable_bindings
.borrow()
.get(index)
.copied()
.unwrap_or_default()
{
return false;
}

self.bindings.borrow_mut()[index] = None;
self.deleted_bindings.borrow_mut()[index] = true;
true
}

/// `BindThisValue`
Expand Down
44 changes: 39 additions & 5 deletions core/engine/src/environments/runtime/declarative/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ impl DeclarativeEnvironment {
self.kind.set(index, value);
}

#[track_caller]
pub(crate) fn delete_binding(&self, index: u32) -> bool {
self.kind.delete_binding(index)
}

#[track_caller]
pub(crate) fn is_deleted_binding(&self, index: u32) -> bool {
self.kind.is_deleted_binding(index)
}

#[track_caller]
pub(crate) fn restore_deleted_binding(&self, index: u32) {
self.kind.restore_deleted_binding(index);
}

/// `GetThisBinding`
///
/// Returns the `this` binding of this environment.
Expand Down Expand Up @@ -132,11 +147,7 @@ impl DeclarativeEnvironment {
/// Extends the environment with the bindings from the compile time environment.
pub(crate) fn extend_from_compile(&self) {
if let Some(env) = self.kind().as_function() {
let compile_bindings_number = env.compile().num_bindings() as usize;
let mut bindings = env.bindings().borrow_mut();
if compile_bindings_number > bindings.len() {
bindings.resize(compile_bindings_number, None);
}
env.extend_from_compile();
}
}
}
Expand Down Expand Up @@ -212,6 +223,29 @@ impl DeclarativeEnvironmentKind {
}
}

#[track_caller]
pub(crate) fn delete_binding(&self, index: u32) -> bool {
match self {
Self::Function(inner) => inner.delete_binding(index),
Self::Lexical(_) | Self::Global(_) | Self::Module(_) => false,
}
}

#[track_caller]
pub(crate) fn is_deleted_binding(&self, index: u32) -> bool {
match self {
Self::Function(inner) => inner.is_deleted_binding(index),
Self::Lexical(_) | Self::Global(_) | Self::Module(_) => false,
}
}

#[track_caller]
pub(crate) fn restore_deleted_binding(&self, index: u32) {
if let Self::Function(inner) = self {
inner.restore_deleted_binding(index);
}
}

/// `GetThisBinding`
///
/// Returns the `this` binding of this environment.
Expand Down
Loading
Loading