mirror of https://github.com/boa-dev/boa.git
Browse Source
This Pull Request fixes #2317 and #1835, finally giving our engine proper realms 🥳. It changes the following: - Extracts the compile environment stack from `Realm` and into `Vm`. - Adjusts the bytecompiler to accommodate this change. - Adjusts `call/construct_internal` to accommodate this change. This also coincidentally fixed #2317, which I'm pretty happy about. - Adjusts several APIs (`NativeJob`, `Realm`) and builtins (`eval`, initializers) to accommodate this change. - Adjusts `JsNativeError`s to hold a reference to the Realm from which they were created. This only affects errors created within calls to function objects. Native calls don't need to set the realm because it's inherited by the next outer active function object. TLDR: `JsError` API stays the same, we just set the origin Realm of errors in `JsObject::call/construct_internal`.pull/2797/head
José Julián Espina
1 year ago
101 changed files with 1768 additions and 1740 deletions
@ -0,0 +1,150 @@ |
|||||||
|
use boa_ast::expression::Identifier; |
||||||
|
use boa_gc::{Gc, GcRefCell}; |
||||||
|
|
||||||
|
use crate::{ |
||||||
|
environments::{BindingLocator, CompileTimeEnvironment}, |
||||||
|
property::PropertyDescriptor, |
||||||
|
JsString, JsValue, |
||||||
|
}; |
||||||
|
|
||||||
|
use super::ByteCompiler; |
||||||
|
|
||||||
|
/// Info returned by the [`ByteCompiler::pop_compile_environment`] method.
|
||||||
|
#[derive(Debug, Clone, Copy)] |
||||||
|
pub(crate) struct PopEnvironmentInfo { |
||||||
|
/// Number of bindings declared.
|
||||||
|
pub(crate) num_bindings: usize, |
||||||
|
/// Index in the compile time envs array.
|
||||||
|
pub(crate) index: usize, |
||||||
|
} |
||||||
|
|
||||||
|
impl ByteCompiler<'_, '_> { |
||||||
|
/// Push either a new declarative or function environment on the compile time environment stack.
|
||||||
|
pub(crate) fn push_compile_environment(&mut self, function_scope: bool) { |
||||||
|
self.current_environment = Gc::new(GcRefCell::new(CompileTimeEnvironment::new( |
||||||
|
self.current_environment.clone(), |
||||||
|
function_scope, |
||||||
|
))); |
||||||
|
} |
||||||
|
|
||||||
|
/// Pops the top compile time environment and returns its index and number of bindings.
|
||||||
|
#[track_caller] |
||||||
|
pub(crate) fn pop_compile_environment(&mut self) -> PopEnvironmentInfo { |
||||||
|
let index = self.compile_environments.len(); |
||||||
|
self.compile_environments |
||||||
|
.push(self.current_environment.clone()); |
||||||
|
|
||||||
|
let (num_bindings, outer) = { |
||||||
|
let env = self.current_environment.borrow(); |
||||||
|
( |
||||||
|
env.num_bindings(), |
||||||
|
env.outer().expect("cannot pop the global environment"), |
||||||
|
) |
||||||
|
}; |
||||||
|
self.current_environment = outer; |
||||||
|
|
||||||
|
PopEnvironmentInfo { |
||||||
|
num_bindings, |
||||||
|
index, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Get the binding locator of the binding at bytecode compile time.
|
||||||
|
pub(crate) fn get_binding_value(&self, name: Identifier) -> BindingLocator { |
||||||
|
self.current_environment |
||||||
|
.borrow() |
||||||
|
.get_binding_recursive(name) |
||||||
|
} |
||||||
|
|
||||||
|
/// Return if a declarative binding exists at bytecode compile time.
|
||||||
|
/// This does not include bindings on the global object.
|
||||||
|
pub(crate) fn has_binding(&self, name: Identifier) -> bool { |
||||||
|
self.current_environment |
||||||
|
.borrow() |
||||||
|
.has_binding_recursive(name) |
||||||
|
} |
||||||
|
|
||||||
|
/// Create a mutable binding at bytecode compile time.
|
||||||
|
/// This function returns a syntax error, if the binding is a redeclaration.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the global environment is not function scoped.
|
||||||
|
pub(crate) fn create_mutable_binding( |
||||||
|
&mut self, |
||||||
|
name: Identifier, |
||||||
|
function_scope: bool, |
||||||
|
configurable: bool, |
||||||
|
) { |
||||||
|
if !self |
||||||
|
.current_environment |
||||||
|
.borrow_mut() |
||||||
|
.create_mutable_binding(name, function_scope) |
||||||
|
{ |
||||||
|
let name_str = self |
||||||
|
.context |
||||||
|
.interner() |
||||||
|
.resolve_expect(name.sym()) |
||||||
|
.into_common::<JsString>(false); |
||||||
|
|
||||||
|
let global_obj = self.context.global_object(); |
||||||
|
|
||||||
|
// TODO: defer global initialization to execution time.
|
||||||
|
if !global_obj |
||||||
|
.has_own_property(name_str.clone(), self.context) |
||||||
|
.unwrap_or_default() |
||||||
|
{ |
||||||
|
global_obj.borrow_mut().insert( |
||||||
|
name_str, |
||||||
|
PropertyDescriptor::builder() |
||||||
|
.value(JsValue::Undefined) |
||||||
|
.writable(true) |
||||||
|
.enumerable(true) |
||||||
|
.configurable(configurable) |
||||||
|
.build(), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Initialize a mutable binding at bytecode compile time and return it's binding locator.
|
||||||
|
pub(crate) fn initialize_mutable_binding( |
||||||
|
&self, |
||||||
|
name: Identifier, |
||||||
|
function_scope: bool, |
||||||
|
) -> BindingLocator { |
||||||
|
self.current_environment |
||||||
|
.borrow() |
||||||
|
.initialize_mutable_binding(name, function_scope) |
||||||
|
} |
||||||
|
|
||||||
|
/// Create an immutable binding at bytecode compile time.
|
||||||
|
/// This function returns a syntax error, if the binding is a redeclaration.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the global environment does not exist.
|
||||||
|
pub(crate) fn create_immutable_binding(&mut self, name: Identifier, strict: bool) { |
||||||
|
self.current_environment |
||||||
|
.borrow_mut() |
||||||
|
.create_immutable_binding(name, strict); |
||||||
|
} |
||||||
|
|
||||||
|
/// Initialize an immutable binding at bytecode compile time and return it's binding locator.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the global environment does not exist or a the binding was not created on the current environment.
|
||||||
|
pub(crate) fn initialize_immutable_binding(&self, name: Identifier) -> BindingLocator { |
||||||
|
self.current_environment |
||||||
|
.borrow() |
||||||
|
.initialize_immutable_binding(name) |
||||||
|
} |
||||||
|
|
||||||
|
/// Return the binding locator for a set operation on an existing binding.
|
||||||
|
pub(crate) fn set_mutable_binding(&self, name: Identifier) -> BindingLocator { |
||||||
|
self.current_environment |
||||||
|
.borrow() |
||||||
|
.set_mutable_binding_recursive(name) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
use indoc::indoc; |
||||||
|
|
||||||
|
use crate::{run_test_actions, TestAction}; |
||||||
|
|
||||||
|
#[test] |
||||||
|
// https://github.com/boa-dev/boa/issues/2317
|
||||||
|
fn fun_block_eval_2317() { |
||||||
|
run_test_actions([ |
||||||
|
TestAction::assert_eq( |
||||||
|
indoc! {r#" |
||||||
|
(function(y){ |
||||||
|
{ |
||||||
|
eval("var x = 'inner';"); |
||||||
|
} |
||||||
|
return y + x; |
||||||
|
})("arg"); |
||||||
|
"#}, |
||||||
|
"arginner", |
||||||
|
), |
||||||
|
TestAction::assert_eq( |
||||||
|
indoc! {r#" |
||||||
|
(function(y = "default"){ |
||||||
|
{ |
||||||
|
eval("var x = 'inner';"); |
||||||
|
} |
||||||
|
return y + x; |
||||||
|
})(); |
||||||
|
"#}, |
||||||
|
"defaultinner", |
||||||
|
), |
||||||
|
]); |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue