diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 3449770cf3..80ff6aaab2 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -17,8 +17,7 @@ use crate::{ builtins::array::array_iterator::{ArrayIterationKind, ArrayIterator}, builtins::BuiltIn, builtins::Number, - gc::GcObject, - object::{ConstructorBuilder, FunctionBuilder, ObjectData, PROTOTYPE}, + object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE}, property::{Attribute, DataDescriptor}, value::{same_value_zero, IntegerOrInfinity, Value}, BoaProfiler, Context, Result, diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index 97a2f8f554..8ae70eec9a 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -126,13 +126,13 @@ impl Function { local_env .borrow_mut() // Function parameters can share names in JavaScript... - .create_mutable_binding(param.name().to_owned(), false, true) + .create_mutable_binding(param.name().to_owned(), false, true, context) .expect("Failed to create binding for rest param"); // Set Binding to value local_env .borrow_mut() - .initialize_binding(param.name(), array) + .initialize_binding(param.name(), array, context) .expect("Failed to initialize rest param"); } @@ -142,17 +142,18 @@ impl Function { param: &FormalParameter, value: Value, local_env: &Environment, + context: &mut Context, ) { // Create binding local_env .borrow_mut() - .create_mutable_binding(param.name().to_owned(), false, true) + .create_mutable_binding(param.name().to_owned(), false, true, context) .expect("Failed to create binding"); // Set Binding to value local_env .borrow_mut() - .initialize_binding(param.name(), value) + .initialize_binding(param.name(), value, context) .expect("Failed to intialize binding"); } diff --git a/boa/src/builtins/global_this/mod.rs b/boa/src/builtins/global_this/mod.rs index bac5b5eccc..ea4a266e6e 100644 --- a/boa/src/builtins/global_this/mod.rs +++ b/boa/src/builtins/global_this/mod.rs @@ -30,7 +30,7 @@ impl BuiltIn for GlobalThis { ( Self::NAME, - context.global_object().clone().into(), + context.global_object().into(), Self::attribute(), ) } diff --git a/boa/src/builtins/map/mod.rs b/boa/src/builtins/map/mod.rs index 3e4e56a455..441694301a 100644 --- a/boa/src/builtins/map/mod.rs +++ b/boa/src/builtins/map/mod.rs @@ -79,12 +79,7 @@ impl Map { } let map_prototype = context .global_object() - .clone() - .get( - &"Map".into(), - context.global_object().clone().into(), - context, - )? + .get(&"Map".into(), context.global_object().into(), context)? .get_field(PROTOTYPE, context)? .as_object() .expect("'Map' global property should be an object"); diff --git a/boa/src/builtins/mod.rs b/boa/src/builtins/mod.rs index 273d50f749..2460b88c6a 100644 --- a/boa/src/builtins/mod.rs +++ b/boa/src/builtins/mod.rs @@ -93,7 +93,7 @@ pub fn init(context: &mut Context) { console::Console::init, ]; - let global_object = context.global_object().clone(); + let global_object = context.global_object(); for init in &globals { let (name, value, attribute) = init(context); diff --git a/boa/src/context.rs b/boa/src/context.rs index e83b76ad9b..4b537fc596 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -210,7 +210,7 @@ impl StandardObjects { #[derive(Debug)] pub struct Context { /// realm holds both the global object and the environment - realm: Realm, + pub(crate) realm: Realm, /// The current executor. executor: Interpreter, @@ -270,16 +270,6 @@ impl Context { Default::default() } - #[inline] - pub fn realm(&self) -> &Realm { - &self.realm - } - - #[inline] - pub fn realm_mut(&mut self) -> &mut Realm { - &mut self.realm - } - #[inline] pub fn executor(&mut self) -> &mut Interpreter { &mut self.executor @@ -340,8 +330,8 @@ impl Context { /// Return the global object. #[inline] - pub fn global_object(&self) -> &GcObject { - &self.realm().global_object + pub fn global_object(&self) -> GcObject { + self.realm.global_object.clone() } /// Constructs a `RangeError` with the specified message. @@ -503,7 +493,7 @@ impl Context { flags, body: RcStatementList::from(body.into()), params, - environment: self.realm.environment.get_current_environment().clone(), + environment: self.get_current_environment().clone(), }; let new_func = Object::function(func, function_prototype); @@ -555,7 +545,7 @@ impl Context { body: NativeFunction, ) -> Result<()> { let function = self.create_builtin_function(name, length, body)?; - let mut global = self.global_object().clone(); + let mut global = self.global_object(); global.insert_property(name, function, Attribute::all()); Ok(()) } @@ -574,10 +564,7 @@ impl Context { pub(crate) fn set_value(&mut self, node: &Node, value: Value) -> Result { match node { Node::Identifier(ref name) => { - self.realm - .environment - .set_mutable_binding(name.as_ref(), value.clone(), true) - .map_err(|e| e.to_error(self))?; + self.set_mutable_binding(name.as_ref(), value.clone(), true)?; Ok(value) } Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node @@ -616,7 +603,7 @@ impl Context { let class = class_builder.build(); let property = DataDescriptor::new(class, T::ATTRIBUTE); - self.global_object().clone().insert(T::NAME, property); + self.global_object().insert(T::NAME, property); Ok(()) } @@ -643,7 +630,7 @@ impl Context { V: Into, { let property = DataDescriptor::new(value, attribute); - self.global_object().clone().insert(key, property); + self.global_object().insert(key, property); } /// Evaluates the given code. diff --git a/boa/src/environment/declarative_environment_record.rs b/boa/src/environment/declarative_environment_record.rs index 0ba2e4f615..6ca3c3918f 100644 --- a/boa/src/environment/declarative_environment_record.rs +++ b/boa/src/environment/declarative_environment_record.rs @@ -5,15 +5,16 @@ //! A declarative Environment Record binds the set of identifiers defined by the declarations contained within its scope. //! More info: [ECMA-262 sec-declarative-environment-records](https://tc39.es/ecma262/#sec-declarative-environment-records) -use super::ErrorKind; use crate::{ environment::{ environment_record_trait::EnvironmentRecordTrait, lexical_environment::{Environment, EnvironmentType}, }, gc::{Finalize, Trace}, - Value, + object::GcObject, + BoaProfiler, Context, Result, Value, }; +use gc::{Gc, GcCell}; use rustc_hash::FxHashMap; /// Declarative Bindings have a few properties for book keeping purposes, such as mutability (const vs let). @@ -33,10 +34,23 @@ pub struct DeclarativeEnvironmentRecordBinding { /// declarations contained within its scope. #[derive(Debug, Trace, Finalize, Clone)] pub struct DeclarativeEnvironmentRecord { - pub env_rec: FxHashMap, + pub env_rec: FxHashMap, DeclarativeEnvironmentRecordBinding>, pub outer_env: Option, } +impl DeclarativeEnvironmentRecord { + #[allow(clippy::new_ret_no_self)] + pub fn new(env: Option) -> Environment { + let _timer = BoaProfiler::global().start_event("new_declarative_environment", "env"); + let boxed_env = Box::new(DeclarativeEnvironmentRecord { + env_rec: FxHashMap::default(), + outer_env: env, + }); + + Gc::new(GcCell::new(boxed_env)) + } +} + impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { fn has_binding(&self, name: &str) -> bool { self.env_rec.contains_key(name) @@ -47,17 +61,18 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + _context: &mut Context, + ) -> Result<()> { if !allow_name_reuse { assert!( - !self.env_rec.contains_key(&name), + !self.env_rec.contains_key(name.as_str()), "Identifier {} has already been declared", name ); } self.env_rec.insert( - name, + name.into_boxed_str(), DeclarativeEnvironmentRecordBinding { value: None, can_delete: deletion, @@ -68,15 +83,20 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { Ok(()) } - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + _context: &mut Context, + ) -> Result<()> { assert!( - !self.env_rec.contains_key(&name), + !self.env_rec.contains_key(name.as_str()), "Identifier {} has already been declared", name ); self.env_rec.insert( - name, + name.into_boxed_str(), DeclarativeEnvironmentRecordBinding { value: None, can_delete: true, @@ -87,7 +107,12 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { Ok(()) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding( + &mut self, + name: &str, + value: Value, + _context: &mut Context, + ) -> Result<()> { if let Some(ref mut record) = self.env_rec.get_mut(name) { if record.value.is_none() { record.value = Some(value); @@ -103,17 +128,15 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { name: &str, value: Value, mut strict: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { if self.env_rec.get(name).is_none() { if strict { - return Err(ErrorKind::new_reference_error(format!( - "{} not found", - name - ))); + return Err(context.construct_reference_error(format!("{} not found", name))); } - self.create_mutable_binding(name.to_owned(), true, false)?; - self.initialize_binding(name, value)?; + self.create_mutable_binding(name.to_owned(), true, false, context)?; + self.initialize_binding(name, value, context)?; return Ok(()); } @@ -122,15 +145,14 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { strict = true } if record.value.is_none() { - return Err(ErrorKind::new_reference_error(format!( - "{} has not been initialized", - name - ))); + return Err( + context.construct_reference_error(format!("{} has not been initialized", name)) + ); } if record.mutable { record.value = Some(value); } else if strict { - return Err(ErrorKind::new_type_error(format!( + return Err(context.construct_reference_error(format!( "Cannot mutate an immutable binding {}", name ))); @@ -139,15 +161,12 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { Ok(()) } - fn get_binding_value(&self, name: &str, _strict: bool) -> Result { + fn get_binding_value(&self, name: &str, _strict: bool, context: &mut Context) -> Result { if let Some(binding) = self.env_rec.get(name) { if let Some(ref val) = binding.value { Ok(val.clone()) } else { - Err(ErrorKind::new_reference_error(format!( - "{} is an uninitialized binding", - name - ))) + context.throw_reference_error(format!("{} is an uninitialized binding", name)) } } else { panic!("Cannot get binding value for {}", name); @@ -172,7 +191,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { false } - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, _context: &mut Context) -> Result { Ok(Value::undefined()) } @@ -180,8 +199,8 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { false } - fn with_base_object(&self) -> Value { - Value::undefined() + fn with_base_object(&self) -> Option { + None } fn get_outer_environment_ref(&self) -> Option<&Environment> { @@ -195,11 +214,4 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { fn get_environment_type(&self) -> EnvironmentType { EnvironmentType::Declarative } - - fn get_global_object(&self) -> Option { - match &self.outer_env { - Some(outer) => outer.borrow().get_global_object(), - None => None, - } - } } diff --git a/boa/src/environment/environment_record_trait.rs b/boa/src/environment/environment_record_trait.rs index 7cc0439a0a..c730d74b64 100644 --- a/boa/src/environment/environment_record_trait.rs +++ b/boa/src/environment/environment_record_trait.rs @@ -8,12 +8,12 @@ //! //! There are 5 Environment record kinds. They all have methods in common, these are implemented as a the `EnvironmentRecordTrait` //! -use super::ErrorKind; -use crate::environment::lexical_environment::VariableScope; + +use crate::{environment::lexical_environment::VariableScope, object::GcObject}; use crate::{ environment::lexical_environment::{Environment, EnvironmentType}, gc::{Finalize, Trace}, - Value, + Context, Result, Value, }; use std::fmt::Debug; @@ -22,7 +22,8 @@ use std::fmt::Debug; /// In the ECMAScript specification Environment Records are hierachical and have a base class with abstract methods. /// In this implementation we have a trait which represents the behaviour of all `EnvironmentRecord` types. pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { - /// Determine if an Environment Record has a binding for the String value N. Return true if it does and false if it does not. + /// Determine if an Environment Record has a binding for the String value N. + /// Return true if it does and false if it does not. fn has_binding(&self, name: &str) -> bool; /// Create a new but uninitialized mutable binding in an Environment Record. The String value N is the text of the bound name. @@ -37,18 +38,25 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind>; + context: &mut Context, + ) -> Result<()>; /// Create a new but uninitialized immutable binding in an Environment Record. /// The String value N is the text of the bound name. /// If strict is true then attempts to set it after it has been initialized will always throw an exception, /// regardless of the strict mode setting of operations that reference that binding. - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind>; + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + context: &mut Context, + ) -> Result<()>; /// Set the value of an already existing but uninitialized binding in an Environment Record. /// The String value N is the text of the bound name. /// V is the value for the binding and is a value of any ECMAScript language type. - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind>; + fn initialize_binding(&mut self, name: &str, value: Value, context: &mut Context) + -> Result<()>; /// Set the value of an already existing mutable binding in an Environment Record. /// The String value `name` is the text of the bound name. @@ -59,13 +67,14 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind>; + context: &mut Context, + ) -> Result<()>; /// Returns the value of an already existing binding from an Environment Record. /// The String value N is the text of the bound name. /// S is used to identify references originating in strict mode code or that /// otherwise require strict mode reference semantics. - fn get_binding_value(&self, name: &str, strict: bool) -> Result; + fn get_binding_value(&self, name: &str, strict: bool, context: &mut Context) -> Result; /// Delete a binding from an Environment Record. /// The String value name is the text of the bound name. @@ -78,15 +87,15 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { fn has_this_binding(&self) -> bool; /// Return the `this` binding from the environment - fn get_this_binding(&self) -> Result; + fn get_this_binding(&self, context: &mut Context) -> Result; /// Determine if an Environment Record establishes a super method binding. /// Return true if it does and false if it does not. fn has_super_binding(&self) -> bool; /// If this Environment Record is associated with a with statement, return the with object. - /// Otherwise, return undefined. - fn with_base_object(&self) -> Value; + /// Otherwise, return None. + fn with_base_object(&self) -> Option; /// Get the next environment up fn get_outer_environment_ref(&self) -> Option<&Environment>; @@ -100,16 +109,13 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { /// Get the type of environment this is fn get_environment_type(&self) -> EnvironmentType; - /// Fetch global variable - fn get_global_object(&self) -> Option; - /// Return the `this` binding from the environment or try to get it from outer environments - fn recursive_get_this_binding(&self) -> Result { + fn recursive_get_this_binding(&self, context: &mut Context) -> Result { if self.has_this_binding() { - self.get_this_binding() + self.get_this_binding(context) } else { match self.get_outer_environment_ref() { - Some(outer) => outer.borrow().recursive_get_this_binding(), + Some(outer) => outer.borrow().recursive_get_this_binding(context), None => Ok(Value::Undefined), } } @@ -121,14 +127,15 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { name: String, deletion: bool, scope: VariableScope, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { match scope { - VariableScope::Block => self.create_mutable_binding(name, deletion, false), + VariableScope::Block => self.create_mutable_binding(name, deletion, false, context), VariableScope::Function => self .get_outer_environment_ref() .expect("No function or global environment") .borrow_mut() - .recursive_create_mutable_binding(name, deletion, scope), + .recursive_create_mutable_binding(name, deletion, scope, context), } } @@ -138,14 +145,15 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { name: String, deletion: bool, scope: VariableScope, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { match scope { - VariableScope::Block => self.create_immutable_binding(name, deletion), + VariableScope::Block => self.create_immutable_binding(name, deletion, context), VariableScope::Function => self .get_outer_environment_ref() .expect("No function or global environment") .borrow_mut() - .recursive_create_immutable_binding(name, deletion, scope), + .recursive_create_immutable_binding(name, deletion, scope, context), } } @@ -155,26 +163,32 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { if self.has_binding(name) { - self.set_mutable_binding(name, value, strict) + self.set_mutable_binding(name, value, strict, context) } else { self.get_outer_environment_ref() .expect("Environment stack underflow") .borrow_mut() - .recursive_set_mutable_binding(name, value, strict) + .recursive_set_mutable_binding(name, value, strict, context) } } /// Initialize binding while handling outer environments - fn recursive_initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn recursive_initialize_binding( + &mut self, + name: &str, + value: Value, + context: &mut Context, + ) -> Result<()> { if self.has_binding(name) { - self.initialize_binding(name, value) + self.initialize_binding(name, value, context) } else { self.get_outer_environment_ref() .expect("Environment stack underflow") .borrow_mut() - .recursive_initialize_binding(name, value) + .recursive_initialize_binding(name, value, context) } } @@ -188,16 +202,13 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { } /// Retrieve binding from current or any outer environment - fn recursive_get_binding_value(&self, name: &str) -> Result { + fn recursive_get_binding_value(&self, name: &str, context: &mut Context) -> Result { if self.has_binding(name) { - self.get_binding_value(name, false) + self.get_binding_value(name, false, context) } else { match self.get_outer_environment_ref() { - Some(outer) => outer.borrow().recursive_get_binding_value(name), - None => Err(ErrorKind::new_reference_error(format!( - "{} is not defined", - name - ))), + Some(outer) => outer.borrow().recursive_get_binding_value(name, context), + None => context.throw_reference_error(format!("{} is not defined", name)), } } } diff --git a/boa/src/environment/function_environment_record.rs b/boa/src/environment/function_environment_record.rs index d0f8228b94..0b28e42fd4 100644 --- a/boa/src/environment/function_environment_record.rs +++ b/boa/src/environment/function_environment_record.rs @@ -8,7 +8,9 @@ //! from within the function. //! More info: -use super::ErrorKind; +use gc::{Gc, GcCell}; +use rustc_hash::FxHashMap; + use crate::{ environment::{ declarative_environment_record::DeclarativeEnvironmentRecord, @@ -17,7 +19,7 @@ use crate::{ }, gc::{empty_trace, Finalize, Trace}, object::GcObject, - Value, + Context, Result, Value, }; /// Different binding status for `this`. @@ -57,17 +59,43 @@ pub struct FunctionEnvironmentRecord { } impl FunctionEnvironmentRecord { - pub fn bind_this_value(&mut self, value: Value) -> Result { + #[allow(clippy::new_ret_no_self)] + pub fn new( + f: GcObject, + this: Option, + outer: Option, + binding_status: BindingStatus, + new_target: Value, + ) -> Environment { + let mut func_env = FunctionEnvironmentRecord { + declarative_record: DeclarativeEnvironmentRecord { + env_rec: FxHashMap::default(), + outer_env: outer, // this will come from Environment set as a private property of F - https://tc39.es/ecma262/#sec-ecmascript-function-objects + }, + function: f, + this_binding_status: binding_status, + home_object: Value::undefined(), + new_target, + this_value: Value::undefined(), + }; + // If a `this` value has been passed, bind it to the environment + if let Some(v) = this { + func_env.bind_this_value(v).unwrap(); + } + Gc::new(GcCell::new(Box::new(func_env))) + } + + pub fn bind_this_value(&mut self, value: Value) -> Result { match self.this_binding_status { // You can not bind an arrow function, their `this` value comes from the lexical scope above BindingStatus::Lexical => { panic!("Cannot bind to an arrow function!"); } // You can not bind a function twice - BindingStatus::Initialized => Err(ErrorKind::new_reference_error( - "Cannot bind to an initialised function!", - )), - + BindingStatus::Initialized => { + todo!(); + // context.throw_reference_error("Cannot bind to an initialised function!") + } BindingStatus::Uninitialized => { self.this_value = value.clone(); self.this_binding_status = BindingStatus::Initialized; @@ -99,18 +127,30 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { self.declarative_record - .create_mutable_binding(name, deletion, allow_name_reuse) + .create_mutable_binding(name, deletion, allow_name_reuse, context) } - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + context: &mut Context, + ) -> Result<()> { self.declarative_record - .create_immutable_binding(name, strict) + .create_immutable_binding(name, strict, context) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { - self.declarative_record.initialize_binding(name, value) + fn initialize_binding( + &mut self, + name: &str, + value: Value, + context: &mut Context, + ) -> Result<()> { + self.declarative_record + .initialize_binding(name, value, context) } fn set_mutable_binding( @@ -118,13 +158,15 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { self.declarative_record - .set_mutable_binding(name, value, strict) + .set_mutable_binding(name, value, strict, context) } - fn get_binding_value(&self, name: &str, _strict: bool) -> Result { - self.declarative_record.get_binding_value(name, _strict) + fn get_binding_value(&self, name: &str, strict: bool, context: &mut Context) -> Result { + self.declarative_record + .get_binding_value(name, strict, context) } fn delete_binding(&mut self, name: &str) -> bool { @@ -135,15 +177,14 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { !matches!(self.this_binding_status, BindingStatus::Lexical) } - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, context: &mut Context) -> Result { match self.this_binding_status { BindingStatus::Lexical => { panic!("There is no this for a lexical function record"); } - BindingStatus::Uninitialized => Err(ErrorKind::new_reference_error( - "Uninitialised binding for this function", - )), - + BindingStatus::Uninitialized => { + context.throw_reference_error("Uninitialised binding for this function") + } BindingStatus::Initialized => Ok(self.this_value.clone()), } } @@ -156,8 +197,8 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { } } - fn with_base_object(&self) -> Value { - Value::undefined() + fn with_base_object(&self) -> Option { + None } fn get_outer_environment_ref(&self) -> Option<&Environment> { @@ -172,17 +213,14 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { EnvironmentType::Function } - fn get_global_object(&self) -> Option { - self.declarative_record.get_global_object() - } - fn recursive_create_mutable_binding( &mut self, name: String, deletion: bool, _scope: VariableScope, - ) -> Result<(), ErrorKind> { - self.create_mutable_binding(name, deletion, false) + context: &mut Context, + ) -> Result<()> { + self.create_mutable_binding(name, deletion, false, context) } fn recursive_create_immutable_binding( @@ -190,7 +228,8 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { name: String, deletion: bool, _scope: VariableScope, - ) -> Result<(), ErrorKind> { - self.create_immutable_binding(name, deletion) + context: &mut Context, + ) -> Result<()> { + self.create_immutable_binding(name, deletion, context) } } diff --git a/boa/src/environment/global_environment_record.rs b/boa/src/environment/global_environment_record.rs index d5443d29b7..2c6c83baf7 100644 --- a/boa/src/environment/global_environment_record.rs +++ b/boa/src/environment/global_environment_record.rs @@ -7,7 +7,6 @@ //! that occur within a Script. //! More info: -use super::ErrorKind; use crate::{ environment::{ declarative_environment_record::DeclarativeEnvironmentRecord, @@ -16,20 +15,48 @@ use crate::{ object_environment_record::ObjectEnvironmentRecord, }, gc::{Finalize, Trace}, + object::GcObject, property::{Attribute, DataDescriptor}, - Value, + Context, Result, Value, }; -use rustc_hash::FxHashSet; +use gc::{Gc, GcCell}; +use rustc_hash::{FxHashMap, FxHashSet}; #[derive(Debug, Trace, Finalize, Clone)] pub struct GlobalEnvironmentRecord { pub object_record: ObjectEnvironmentRecord, - pub global_this_binding: Value, + pub global_this_binding: GcObject, pub declarative_record: DeclarativeEnvironmentRecord, - pub var_names: FxHashSet, + pub var_names: FxHashSet>, } impl GlobalEnvironmentRecord { + #[allow(clippy::new_ret_no_self)] + pub fn new(global: GcObject, this_value: GcObject) -> Environment { + let obj_rec = ObjectEnvironmentRecord { + bindings: global.into(), + outer_env: None, + /// Object Environment Records created for with statements (13.11) + /// can provide their binding object as an implicit this value for use in function calls. + /// The capability is controlled by a withEnvironment Boolean value that is associated + /// with each object Environment Record. By default, the value of withEnvironment is false + /// for any object Environment Record. + with_environment: false, + }; + + let dcl_rec = DeclarativeEnvironmentRecord { + env_rec: FxHashMap::default(), + outer_env: None, + }; + + Gc::new(GcCell::new(Box::new(GlobalEnvironmentRecord { + object_record: obj_rec, + global_this_binding: this_value, + declarative_record: dcl_rec, + var_names: FxHashSet::default(), + }))) + } + pub fn has_var_declaration(&self, name: &str) -> bool { self.var_names.contains(name) } @@ -80,19 +107,20 @@ impl GlobalEnvironmentRecord { &mut self, name: String, deletion: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { let obj_rec = &mut self.object_record; let global_object = &obj_rec.bindings; let has_property = global_object.has_field(name.as_str()); let extensible = global_object.is_extensible(); if !has_property && extensible { - obj_rec.create_mutable_binding(name.clone(), deletion, false)?; - obj_rec.initialize_binding(&name, Value::undefined())?; + obj_rec.create_mutable_binding(name.clone(), deletion, false, context)?; + obj_rec.initialize_binding(&name, Value::undefined(), context)?; } let var_declared_names = &mut self.var_names; - if !var_declared_names.contains(&name) { - var_declared_names.insert(name); + if !var_declared_names.contains(name.as_str()) { + var_declared_names.insert(name.into_boxed_str()); } Ok(()) } @@ -132,40 +160,51 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { if !allow_name_reuse && self.declarative_record.has_binding(&name) { - return Err(ErrorKind::new_type_error(format!( - "Binding already exists for {}", - name - ))); + return Err( + context.construct_type_error(format!("Binding already exists for {}", name)) + ); } self.declarative_record - .create_mutable_binding(name, deletion, allow_name_reuse) + .create_mutable_binding(name, deletion, allow_name_reuse, context) } - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + context: &mut Context, + ) -> Result<()> { if self.declarative_record.has_binding(&name) { - return Err(ErrorKind::new_type_error(format!( - "Binding already exists for {}", - name - ))); + return Err( + context.construct_type_error(format!("Binding already exists for {}", name)) + ); } self.declarative_record - .create_immutable_binding(name, strict) + .create_immutable_binding(name, strict, context) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding( + &mut self, + name: &str, + value: Value, + context: &mut Context, + ) -> Result<()> { if self.declarative_record.has_binding(&name) { - return self.declarative_record.initialize_binding(name, value); + return self + .declarative_record + .initialize_binding(name, value, context); } assert!( self.object_record.has_binding(name), "Binding must be in object_record" ); - self.object_record.initialize_binding(name, value) + self.object_record.initialize_binding(name, value, context) } fn set_mutable_binding( @@ -173,20 +212,24 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { if self.declarative_record.has_binding(&name) { return self .declarative_record - .set_mutable_binding(name, value, strict); + .set_mutable_binding(name, value, strict, context); } - self.object_record.set_mutable_binding(name, value, strict) + self.object_record + .set_mutable_binding(name, value, strict, context) } - fn get_binding_value(&self, name: &str, strict: bool) -> Result { + fn get_binding_value(&self, name: &str, strict: bool, context: &mut Context) -> Result { if self.declarative_record.has_binding(&name) { - return self.declarative_record.get_binding_value(name, strict); + return self + .declarative_record + .get_binding_value(name, strict, context); } - self.object_record.get_binding_value(name, strict) + self.object_record.get_binding_value(name, strict, context) } fn delete_binding(&mut self, name: &str) -> bool { @@ -212,16 +255,16 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { true } - fn get_this_binding(&self) -> Result { - Ok(self.global_this_binding.clone()) + fn get_this_binding(&self, _context: &mut Context) -> Result { + Ok(self.global_this_binding.clone().into()) } fn has_super_binding(&self) -> bool { false } - fn with_base_object(&self) -> Value { - Value::undefined() + fn with_base_object(&self) -> Option { + None } fn get_outer_environment(&self) -> Option { @@ -241,17 +284,14 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { EnvironmentType::Global } - fn get_global_object(&self) -> Option { - Some(self.global_this_binding.clone()) - } - fn recursive_create_mutable_binding( &mut self, name: String, deletion: bool, _scope: VariableScope, - ) -> Result<(), ErrorKind> { - self.create_mutable_binding(name, deletion, false) + context: &mut Context, + ) -> Result<()> { + self.create_mutable_binding(name, deletion, false, context) } fn recursive_create_immutable_binding( @@ -259,8 +299,9 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { name: String, deletion: bool, _scope: VariableScope, - ) -> Result<(), ErrorKind> { - self.create_immutable_binding(name, deletion) + context: &mut Context, + ) -> Result<()> { + self.create_immutable_binding(name, deletion, context) } fn recursive_set_mutable_binding( @@ -268,11 +309,17 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { - self.set_mutable_binding(name, value, strict) + context: &mut Context, + ) -> Result<()> { + self.set_mutable_binding(name, value, strict, context) } - fn recursive_initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { - self.initialize_binding(name, value) + fn recursive_initialize_binding( + &mut self, + name: &str, + value: Value, + context: &mut Context, + ) -> Result<()> { + self.initialize_binding(name, value, context) } } diff --git a/boa/src/environment/lexical_environment.rs b/boa/src/environment/lexical_environment.rs index cd758ac5b6..fdf4b8a97b 100644 --- a/boa/src/environment/lexical_environment.rs +++ b/boa/src/environment/lexical_environment.rs @@ -5,20 +5,12 @@ //! The following operations are used to operate upon lexical environments //! This is the entrypoint to lexical environments. -use super::ErrorKind; +use super::global_environment_record::GlobalEnvironmentRecord; use crate::{ - environment::{ - declarative_environment_record::DeclarativeEnvironmentRecord, - environment_record_trait::EnvironmentRecordTrait, - function_environment_record::{BindingStatus, FunctionEnvironmentRecord}, - global_environment_record::GlobalEnvironmentRecord, - object_environment_record::ObjectEnvironmentRecord, - }, - object::GcObject, - BoaProfiler, Value, + environment::environment_record_trait::EnvironmentRecordTrait, object::GcObject, BoaProfiler, + Context, Result, Value, }; use gc::{Gc, GcCell}; -use rustc_hash::{FxHashMap, FxHashSet}; use std::{collections::VecDeque, error, fmt}; /// Environments are wrapped in a Box and then in a GC wrapper @@ -68,21 +60,12 @@ impl fmt::Display for EnvironmentError { } } -impl error::Error for EnvironmentError { - fn description(&self) -> &str { - &self.details - } - - fn cause(&self) -> Option<&dyn error::Error> { - // Generic error, underlying cause isn't tracked. - None - } -} +impl error::Error for EnvironmentError {} impl LexicalEnvironment { - pub fn new(global: Value) -> Self { + pub fn new(global: GcObject) -> Self { let _timer = BoaProfiler::global().start_event("LexicalEnvironment::new", "env"); - let global_env = new_global_environment(global.clone(), global); + let global_env = GlobalEnvironmentRecord::new(global.clone(), global); let mut lexical_env = Self { environment_stack: VecDeque::new(), }; @@ -91,168 +74,86 @@ impl LexicalEnvironment { lexical_env.environment_stack.push_back(global_env); lexical_env } +} - pub fn push(&mut self, env: Environment) { - self.environment_stack.push_back(env); - } - - pub fn pop(&mut self) -> Option { - self.environment_stack.pop_back() +impl Context { + pub(crate) fn push_environment(&mut self, env: Environment) { + self.realm.environment.environment_stack.push_back(env); } - pub fn get_global_object(&self) -> Option { - self.get_current_environment_ref() - .borrow() - .get_global_object() + pub(crate) fn pop_environment(&mut self) -> Option { + self.realm.environment.environment_stack.pop_back() } - pub fn get_this_binding(&self) -> Result { - self.get_current_environment_ref() + pub(crate) fn get_this_binding(&mut self) -> Result { + self.get_current_environment() .borrow() - .recursive_get_this_binding() + .recursive_get_this_binding(self) } - pub fn create_mutable_binding( + pub(crate) fn create_mutable_binding( &mut self, name: String, deletion: bool, scope: VariableScope, - ) -> Result<(), ErrorKind> { + ) -> Result<()> { self.get_current_environment() .borrow_mut() - .recursive_create_mutable_binding(name, deletion, scope) + .recursive_create_mutable_binding(name, deletion, scope, self) } - pub fn create_immutable_binding( + pub(crate) fn create_immutable_binding( &mut self, name: String, deletion: bool, scope: VariableScope, - ) -> Result<(), ErrorKind> { + ) -> Result<()> { self.get_current_environment() .borrow_mut() - .recursive_create_immutable_binding(name, deletion, scope) + .recursive_create_immutable_binding(name, deletion, scope, self) } - pub fn set_mutable_binding( + pub(crate) fn set_mutable_binding( &mut self, name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + ) -> Result<()> { self.get_current_environment() .borrow_mut() - .recursive_set_mutable_binding(name, value, strict) + .recursive_set_mutable_binding(name, value, strict, self) } - pub fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + pub(crate) fn initialize_binding(&mut self, name: &str, value: Value) -> Result<()> { self.get_current_environment() .borrow_mut() - .recursive_initialize_binding(name, value) - } - - /// get_current_environment_ref is used when you only need to borrow the environment - /// (you only need to add a new variable binding, or you want to fetch a value) - pub fn get_current_environment_ref(&self) -> &Environment { - self.environment_stack - .back() - .expect("Could not get current environment") + .recursive_initialize_binding(name, value, self) } /// When neededing to clone an environment (linking it with another environnment) /// cloning is more suited. The GC will remove the env once nothing is linking to it anymore - pub fn get_current_environment(&mut self) -> &mut Environment { - self.environment_stack + pub(crate) fn get_current_environment(&mut self) -> Environment { + self.realm + .environment + .environment_stack .back_mut() .expect("Could not get mutable reference to back object") + .clone() } - pub fn has_binding(&self, name: &str) -> bool { - self.get_current_environment_ref() + pub(crate) fn has_binding(&mut self, name: &str) -> bool { + self.get_current_environment() .borrow() .recursive_has_binding(name) } - pub fn get_binding_value(&self, name: &str) -> Result { - self.get_current_environment_ref() + pub(crate) fn get_binding_value(&mut self, name: &str) -> Result { + self.get_current_environment() .borrow() - .recursive_get_binding_value(name) + .recursive_get_binding_value(name, self) } } -pub fn new_declarative_environment(env: Option) -> Environment { - let _timer = BoaProfiler::global().start_event("new_declarative_environment", "env"); - let boxed_env = Box::new(DeclarativeEnvironmentRecord { - env_rec: FxHashMap::default(), - outer_env: env, - }); - - Gc::new(GcCell::new(boxed_env)) -} - -pub fn new_function_environment( - f: GcObject, - this: Option, - outer: Option, - binding_status: BindingStatus, - new_target: Value, -) -> Environment { - let mut func_env = FunctionEnvironmentRecord { - declarative_record: DeclarativeEnvironmentRecord { - env_rec: FxHashMap::default(), - outer_env: outer, // this will come from Environment set as a private property of F - https://tc39.es/ecma262/#sec-ecmascript-function-objects - }, - function: f, - this_binding_status: binding_status, - home_object: Value::undefined(), - new_target, - this_value: Value::undefined(), - }; - // If a `this` value has been passed, bind it to the environment - if let Some(v) = this { - func_env.bind_this_value(v).unwrap(); - } - Gc::new(GcCell::new(Box::new(func_env))) -} - -pub fn new_object_environment(object: Value, environment: Option) -> Environment { - Gc::new(GcCell::new(Box::new(ObjectEnvironmentRecord { - bindings: object, - outer_env: environment, - /// Object Environment Records created for with statements (13.11) - /// can provide their binding object as an implicit this value for use in function calls. - /// The capability is controlled by a withEnvironment Boolean value that is associated - /// with each object Environment Record. By default, the value of withEnvironment is false - /// for any object Environment Record. - with_environment: false, - }))) -} - -pub fn new_global_environment(global: Value, this_value: Value) -> Environment { - let obj_rec = ObjectEnvironmentRecord { - bindings: global, - outer_env: None, - /// Object Environment Records created for with statements (13.11) - /// can provide their binding object as an implicit this value for use in function calls. - /// The capability is controlled by a withEnvironment Boolean value that is associated - /// with each object Environment Record. By default, the value of withEnvironment is false - /// for any object Environment Record. - with_environment: false, - }; - - let dcl_rec = DeclarativeEnvironmentRecord { - env_rec: FxHashMap::default(), - outer_env: None, - }; - - Gc::new(GcCell::new(Box::new(GlobalEnvironmentRecord { - object_record: obj_rec, - global_this_binding: this_value, - declarative_record: dcl_rec, - var_names: FxHashSet::default(), - }))) -} - #[cfg(test)] mod tests { use crate::exec; diff --git a/boa/src/environment/mod.rs b/boa/src/environment/mod.rs index ceb1773c38..3e4d89bbeb 100644 --- a/boa/src/environment/mod.rs +++ b/boa/src/environment/mod.rs @@ -6,35 +6,3 @@ pub mod function_environment_record; pub mod global_environment_record; pub mod lexical_environment; pub mod object_environment_record; - -#[derive(Debug)] -pub enum ErrorKind { - ReferenceError(Box), - TypeError(Box), -} - -use crate::value::Value; -use crate::Context; - -impl ErrorKind { - pub fn to_error(&self, ctx: &mut Context) -> Value { - match self { - ErrorKind::ReferenceError(msg) => ctx.construct_reference_error(msg.clone()), - ErrorKind::TypeError(msg) => ctx.construct_type_error(msg.clone()), - } - } - - pub fn new_reference_error(msg: M) -> Self - where - M: Into>, - { - Self::ReferenceError(msg.into()) - } - - pub fn new_type_error(msg: M) -> Self - where - M: Into>, - { - Self::TypeError(msg.into()) - } -} diff --git a/boa/src/environment/object_environment_record.rs b/boa/src/environment/object_environment_record.rs index b2e83ee031..75f70f35aa 100644 --- a/boa/src/environment/object_environment_record.rs +++ b/boa/src/environment/object_environment_record.rs @@ -6,25 +6,44 @@ //! Property keys that are not strings in the form of an `IdentifierName` are not included in the set of bound identifiers. //! More info: [Object Records](https://tc39.es/ecma262/#sec-object-environment-records) -use super::*; -use crate::property::PropertyDescriptor; +use gc::{Gc, GcCell}; + use crate::{ environment::{ environment_record_trait::EnvironmentRecordTrait, lexical_environment::{Environment, EnvironmentType}, }, gc::{Finalize, Trace}, + object::GcObject, + property::PropertyDescriptor, property::{Attribute, DataDescriptor}, - Value, + Context, Result, Value, }; #[derive(Debug, Trace, Finalize, Clone)] pub struct ObjectEnvironmentRecord { + // TODO: bindings should be an object. pub bindings: Value, pub with_environment: bool, pub outer_env: Option, } +impl ObjectEnvironmentRecord { + #[allow(clippy::new_ret_no_self)] + pub fn new(object: Value, environment: Option) -> Environment { + Gc::new(GcCell::new(Box::new(ObjectEnvironmentRecord { + bindings: object, + outer_env: environment, + /// Object Environment Records created for with statements (13.11) + /// can provide their binding object as an implicit this value for use in function calls. + /// The capability is controlled by a withEnvironment Boolean value that is associated + /// with each object Environment Record. By default, the value of withEnvironment is false + /// for any object Environment Record. + with_environment: false, + }))) + } +} + impl EnvironmentRecordTrait for ObjectEnvironmentRecord { fn has_binding(&self, name: &str) -> bool { if self.bindings.has_field(name) { @@ -42,7 +61,8 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { name: String, deletion: bool, _allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + _context: &mut Context, + ) -> Result<()> { // TODO: could save time here and not bother generating a new undefined object, // only for it to be replace with the real value later. We could just add the name to a Vector instead let bindings = &mut self.bindings; @@ -56,16 +76,26 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { Ok(()) } - fn create_immutable_binding(&mut self, _name: String, _strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + _name: String, + _strict: bool, + _context: &mut Context, + ) -> Result<()> { Ok(()) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding( + &mut self, + name: &str, + value: Value, + context: &mut Context, + ) -> Result<()> { // We should never need to check if a binding has been created, // As all calls to create_mutable_binding are followed by initialized binding // The below is just a check. debug_assert!(self.has_binding(&name)); - self.set_mutable_binding(name, value, false) + self.set_mutable_binding(name, value, false, context) } fn set_mutable_binding( @@ -73,7 +103,8 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + _context: &mut Context, + ) -> Result<()> { debug_assert!(value.is_object() || value.is_function()); let mut property = DataDescriptor::new(value, Attribute::ENUMERABLE); property.set_configurable(strict); @@ -84,17 +115,14 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { Ok(()) } - fn get_binding_value(&self, name: &str, strict: bool) -> Result { + fn get_binding_value(&self, name: &str, strict: bool, context: &mut Context) -> Result { if self.bindings.has_field(name) { match self.bindings.get_property(name) { Some(PropertyDescriptor::Data(ref d)) => Ok(d.value()), _ => Ok(Value::undefined()), } } else if strict { - Err(ErrorKind::new_reference_error(format!( - "{} has no binding", - name - ))) + context.throw_reference_error(format!("{} has no binding", name)) } else { Ok(Value::undefined()) } @@ -109,7 +137,7 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { false } - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, _context: &mut Context) -> Result { Ok(Value::undefined()) } @@ -117,14 +145,14 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { false } - fn with_base_object(&self) -> Value { + fn with_base_object(&self) -> Option { // Object Environment Records return undefined as their // WithBaseObject unless their withEnvironment flag is true. if self.with_environment { - return self.bindings.clone(); + return Some(self.bindings.as_object().unwrap()); } - Value::undefined() + None } fn get_outer_environment_ref(&self) -> Option<&Environment> { @@ -138,12 +166,4 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { fn get_environment_type(&self) -> EnvironmentType { EnvironmentType::Function } - - fn get_global_object(&self) -> Option { - if let Some(outer) = &self.outer_env { - outer.borrow().get_global_object() - } else { - None - } - } } diff --git a/boa/src/gc.rs b/boa/src/gc.rs index c9586ba19c..7cf585edaa 100644 --- a/boa/src/gc.rs +++ b/boa/src/gc.rs @@ -4,7 +4,6 @@ // when it should be `empty_trace`. #![allow(clippy::unsafe_removed_from_name)] -pub use crate::object::GcObject; pub use gc::{ custom_trace, force_collect, unsafe_empty_trace as empty_trace, Finalize, GcCellRef as Ref, GcCellRefMut as RefMut, Trace, diff --git a/boa/src/object/gcobject.rs b/boa/src/object/gcobject.rs index bb1135e4dc..5a7a0d0587 100644 --- a/boa/src/object/gcobject.rs +++ b/boa/src/object/gcobject.rs @@ -7,9 +7,7 @@ use crate::{ builtins::function::{ create_unmapped_arguments_object, BuiltInFunction, Function, NativeFunction, }, - environment::{ - function_environment_record::BindingStatus, lexical_environment::new_function_environment, - }, + environment::function_environment_record::{BindingStatus, FunctionEnvironmentRecord}, property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, syntax::ast::node::RcStatementList, value::PreferredType, @@ -135,7 +133,7 @@ impl GcObject { } => { // Create a new Function environment whose parent is set to the scope of the function declaration (self.environment) // - let local_env = new_function_environment( + let local_env = FunctionEnvironmentRecord::new( this_function_object, if flags.is_lexical_this_mode() { None @@ -161,21 +159,25 @@ impl GcObject { } let value = args.get(i).cloned().unwrap_or_else(Value::undefined); - function.add_arguments_to_environment(param, value, &local_env); + function + .add_arguments_to_environment(param, value, &local_env, context); } // Add arguments object let arguments_obj = create_unmapped_arguments_object(args); - local_env - .borrow_mut() - .create_mutable_binding("arguments".to_string(), false, true) - .map_err(|e| e.to_error(context))?; - local_env - .borrow_mut() - .initialize_binding("arguments", arguments_obj) - .map_err(|e| e.to_error(context))?; + local_env.borrow_mut().create_mutable_binding( + "arguments".to_string(), + false, + true, + context, + )?; + local_env.borrow_mut().initialize_binding( + "arguments", + arguments_obj, + context, + )?; - context.realm_mut().environment.push(local_env); + context.push_environment(local_env); FunctionBody::Ordinary(body.clone()) } @@ -192,7 +194,7 @@ impl GcObject { FunctionBody::BuiltInConstructor(func) => func(&Value::undefined(), args, context), FunctionBody::Ordinary(body) => { let result = body.run(context); - context.realm_mut().environment.pop(); + context.pop_environment(); result } @@ -247,7 +249,7 @@ impl GcObject { // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment) // - let local_env = new_function_environment( + let local_env = FunctionEnvironmentRecord::new( this_function_object, Some(this), Some(environment.clone()), @@ -269,21 +271,24 @@ impl GcObject { } let value = args.get(i).cloned().unwrap_or_else(Value::undefined); - function.add_arguments_to_environment(param, value, &local_env); + function + .add_arguments_to_environment(param, value, &local_env, context); } // Add arguments object let arguments_obj = create_unmapped_arguments_object(args); - local_env - .borrow_mut() - .create_mutable_binding("arguments".to_string(), false, true) - .map_err(|e| e.to_error(context))?; - local_env - .borrow_mut() - .initialize_binding("arguments", arguments_obj) - .map_err(|e| e.to_error(context))?; - - context.realm_mut().environment.push(local_env); + local_env.borrow_mut().create_mutable_binding( + "arguments".to_string(), + false, + true, + context, + )?; + local_env.borrow_mut().initialize_binding( + "arguments", + arguments_obj, + context, + )?; + context.push_environment(local_env); FunctionBody::Ordinary(body.clone()) } @@ -305,12 +310,8 @@ impl GcObject { let _ = body.run(context); // local_env gets dropped here, its no longer needed - let result = context - .realm_mut() - .environment - .get_this_binding() - .map_err(|e| e.to_error(context)); - context.realm_mut().environment.pop(); + let result = context.get_this_binding(); + context.pop_environment(); result } FunctionBody::BuiltInFunction(_) => unreachable!("Cannot have a function in construct"), diff --git a/boa/src/realm.rs b/boa/src/realm.rs index 0afe038b63..6f40e41fd4 100644 --- a/boa/src/realm.rs +++ b/boa/src/realm.rs @@ -4,7 +4,6 @@ //! //! A realm is represented in this implementation as a Realm struct with the fields specified from the spec. -use crate::object::{GcObject, Object, ObjectData}; use crate::{ environment::{ declarative_environment_record::DeclarativeEnvironmentRecord, @@ -12,7 +11,8 @@ use crate::{ lexical_environment::LexicalEnvironment, object_environment_record::ObjectEnvironmentRecord, }, - BoaProfiler, Value, + object::{GcObject, Object, ObjectData}, + BoaProfiler, }; use gc::{Gc, GcCell}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -41,12 +41,12 @@ impl Realm { let gc_global = GcObject::new(global); // We need to clone the global here because its referenced from separate places (only pointer is cloned) - let global_env = new_global_environment(gc_global.clone(), gc_global.clone().into()); + let global_env = new_global_environment(gc_global.clone(), gc_global.clone()); Self { global_object: gc_global.clone(), global_env, - environment: LexicalEnvironment::new(gc_global.into()), + environment: LexicalEnvironment::new(gc_global), } } } @@ -54,10 +54,10 @@ impl Realm { // Similar to new_global_environment in lexical_environment, except we need to return a GlobalEnvirionment fn new_global_environment( global: GcObject, - this_value: Value, + this_value: GcObject, ) -> Gc> { let obj_rec = ObjectEnvironmentRecord { - bindings: Value::Object(global), + bindings: global.into(), outer_env: None, /// Object Environment Records created for with statements (13.11) /// can provide their binding object as an implicit this value for use in function calls. diff --git a/boa/src/syntax/ast/node/block/mod.rs b/boa/src/syntax/ast/node/block/mod.rs index c87fbbb35c..39c19f88e1 100644 --- a/boa/src/syntax/ast/node/block/mod.rs +++ b/boa/src/syntax/ast/node/block/mod.rs @@ -2,7 +2,7 @@ use super::{Node, StatementList}; use crate::{ - environment::lexical_environment::new_declarative_environment, + environment::declarative_environment_record::DeclarativeEnvironmentRecord, exec::Executable, exec::InterpreterState, gc::{Finalize, Trace}, @@ -54,10 +54,8 @@ impl Executable for Block { fn run(&self, context: &mut Context) -> Result { let _timer = BoaProfiler::global().start_event("Block", "exec"); { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = context.get_current_environment(); + context.push_environment(DeclarativeEnvironmentRecord::new(Some(env))); } // https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation @@ -67,7 +65,7 @@ impl Executable for Block { obj = statement.run(context).map_err(|e| { // No matter how control leaves the Block the LexicalEnvironment is always // restored to its former state. - context.realm_mut().environment.pop(); + context.pop_environment(); e })?; @@ -93,7 +91,7 @@ impl Executable for Block { } // pop the block env - let _ = context.realm_mut().environment.pop(); + let _ = context.pop_environment(); Ok(obj) } diff --git a/boa/src/syntax/ast/node/call/mod.rs b/boa/src/syntax/ast/node/call/mod.rs index 716994743c..d6f1b6eba3 100644 --- a/boa/src/syntax/ast/node/call/mod.rs +++ b/boa/src/syntax/ast/node/call/mod.rs @@ -84,7 +84,7 @@ impl Executable for Call { } _ => ( // 'this' binding should come from the function's self-contained environment - context.global_object().clone().into(), + context.global_object().into(), self.expr().run(context)?, ), }; diff --git a/boa/src/syntax/ast/node/declaration/function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/function_decl/mod.rs index 999faebdd4..e3b68bc767 100644 --- a/boa/src/syntax/ast/node/declaration/function_decl/mod.rs +++ b/boa/src/syntax/ast/node/declaration/function_decl/mod.rs @@ -95,21 +95,16 @@ impl Executable for FunctionDecl { // Set the name and assign it in the current environment val.set_field("name", self.name(), context)?; - let environment = &mut context.realm_mut().environment; - if environment.has_binding(self.name()) { - environment - .set_mutable_binding(self.name(), val, true) - .map_err(|e| e.to_error(context))?; + if context.has_binding(self.name()) { + context.set_mutable_binding(self.name(), val, true)?; } else { - environment - .create_mutable_binding(self.name().to_owned(), false, VariableScope::Function) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + self.name().to_owned(), + false, + VariableScope::Function, + )?; - context - .realm_mut() - .environment - .initialize_binding(self.name(), val) - .map_err(|e| e.to_error(context))?; + context.initialize_binding(self.name(), val)?; } Ok(Value::undefined()) } diff --git a/boa/src/syntax/ast/node/declaration/mod.rs b/boa/src/syntax/ast/node/declaration/mod.rs index b63fb4c8d7..c81906e8ed 100644 --- a/boa/src/syntax/ast/node/declaration/mod.rs +++ b/boa/src/syntax/ast/node/declaration/mod.rs @@ -101,33 +101,31 @@ impl Executable for DeclarationList { None => Value::undefined(), }; - let environment = &mut context.realm_mut().environment; - - if self.is_var() && environment.has_binding(decl.name()) { + if self.is_var() && context.has_binding(decl.name()) { if decl.init().is_some() { - environment - .set_mutable_binding(decl.name(), val, true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(decl.name(), val, true)?; } continue; } match &self { - Const(_) => environment - .create_immutable_binding(decl.name().to_owned(), false, VariableScope::Block) - .map_err(|e| e.to_error(context))?, - Let(_) => environment - .create_mutable_binding(decl.name().to_owned(), false, VariableScope::Block) - .map_err(|e| e.to_error(context))?, - Var(_) => environment - .create_mutable_binding(decl.name().to_owned(), false, VariableScope::Function) - .map_err(|e| e.to_error(context))?, + Const(_) => context.create_immutable_binding( + decl.name().to_owned(), + false, + VariableScope::Block, + )?, + Let(_) => context.create_mutable_binding( + decl.name().to_owned(), + false, + VariableScope::Block, + )?, + Var(_) => context.create_mutable_binding( + decl.name().to_owned(), + false, + VariableScope::Function, + )?, } - context - .realm_mut() - .environment - .initialize_binding(decl.name(), val) - .map_err(|e| e.to_error(context))?; + context.initialize_binding(decl.name(), val)?; } Ok(Value::undefined()) diff --git a/boa/src/syntax/ast/node/identifier/mod.rs b/boa/src/syntax/ast/node/identifier/mod.rs index 25f46b6647..ca595d460e 100644 --- a/boa/src/syntax/ast/node/identifier/mod.rs +++ b/boa/src/syntax/ast/node/identifier/mod.rs @@ -36,11 +36,7 @@ pub struct Identifier { impl Executable for Identifier { fn run(&self, context: &mut Context) -> Result { - context - .realm() - .environment - .get_binding_value(self.as_ref()) - .map_err(|e| e.to_error(context)) + context.get_binding_value(self.as_ref()) } } diff --git a/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs b/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs index 22caa67fc4..1b2e53988b 100644 --- a/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs @@ -1,6 +1,9 @@ use crate::{ builtins::{iterable::IteratorRecord, ForInIterator}, - environment::lexical_environment::{new_declarative_environment, VariableScope}, + environment::{ + declarative_environment_record::DeclarativeEnvironmentRecord, + lexical_environment::VariableScope, + }, exec::{Executable, InterpreterState}, gc::{Finalize, Trace}, syntax::ast::node::Node, @@ -93,65 +96,45 @@ impl Executable for ForInLoop { loop { { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = context.get_current_environment(); + context.push_environment(DeclarativeEnvironmentRecord::new(Some(env))); } let iterator_result = iterator.next(context)?; if iterator_result.is_done() { - context.realm_mut().environment.pop(); + context.pop_environment(); break; } let next_result = iterator_result.value(); match self.variable() { Node::Identifier(ref name) => { - let environment = &mut context.realm_mut().environment; - - if environment.has_binding(name.as_ref()) { + if context.has_binding(name.as_ref()) { // Binding already exists - environment - .set_mutable_binding(name.as_ref(), next_result.clone(), true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(name.as_ref(), next_result.clone(), true)?; } else { - environment - .create_mutable_binding( - name.as_ref().to_owned(), - true, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(name.as_ref(), next_result.clone()) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + name.as_ref().to_owned(), + true, + VariableScope::Function, + )?; + context.initialize_binding(name.as_ref(), next_result.clone())?; } } Node::VarDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; - if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-in loop can't have an initializer"); } - if environment.has_binding(var.name()) { - environment - .set_mutable_binding(var.name(), next_result, true) - .map_err(|e| e.to_error(context))?; + if context.has_binding(var.name()) { + context.set_mutable_binding(var.name(), next_result, true)?; } else { - environment - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Function, + )?; + context.initialize_binding(var.name(), next_result)?; } } _ => { @@ -162,23 +145,16 @@ impl Executable for ForInLoop { }, Node::LetDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; - if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-in loop can't have an initializer"); } - environment - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + )?; + context.initialize_binding(var.name(), next_result)?; } _ => { return context.throw_syntax_error( @@ -188,23 +164,16 @@ impl Executable for ForInLoop { }, Node::ConstDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; - if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-in loop can't have an initializer"); } - environment - .create_immutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_immutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + )?; + context.initialize_binding(var.name(), next_result)?; } _ => { return context.throw_syntax_error( @@ -237,7 +206,7 @@ impl Executable for ForInLoop { // Continue execution. } } - let _ = context.realm_mut().environment.pop(); + let _ = context.pop_environment(); } Ok(result) } diff --git a/boa/src/syntax/ast/node/iteration/for_loop/mod.rs b/boa/src/syntax/ast/node/iteration/for_loop/mod.rs index 4936c8b072..dd69027354 100644 --- a/boa/src/syntax/ast/node/iteration/for_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/for_loop/mod.rs @@ -1,5 +1,5 @@ use crate::{ - environment::lexical_environment::new_declarative_environment, + environment::declarative_environment_record::DeclarativeEnvironmentRecord, exec::{Executable, InterpreterState}, gc::{Finalize, Trace}, syntax::ast::node::Node, @@ -102,10 +102,8 @@ impl Executable for ForLoop { // Create the block environment. let _timer = BoaProfiler::global().start_event("ForLoop", "exec"); { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = context.get_current_environment(); + context.push_environment(DeclarativeEnvironmentRecord::new(Some(env))); } if let Some(init) = self.init() { @@ -143,7 +141,7 @@ impl Executable for ForLoop { } // pop the block env - let _ = context.realm_mut().environment.pop(); + let _ = context.pop_environment(); Ok(Value::undefined()) } diff --git a/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs b/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs index eea1aad38b..9db251e91a 100644 --- a/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs @@ -1,6 +1,9 @@ use crate::{ builtins::iterable::get_iterator, - environment::lexical_environment::{new_declarative_environment, VariableScope}, + environment::{ + declarative_environment_record::DeclarativeEnvironmentRecord, + lexical_environment::VariableScope, + }, exec::{Executable, InterpreterState}, gc::{Finalize, Trace}, syntax::ast::node::Node, @@ -83,65 +86,45 @@ impl Executable for ForOfLoop { loop { { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = context.get_current_environment(); + context.push_environment(DeclarativeEnvironmentRecord::new(Some(env))); } let iterator_result = iterator.next(context)?; if iterator_result.is_done() { - context.realm_mut().environment.pop(); + context.pop_environment(); break; } let next_result = iterator_result.value(); match self.variable() { Node::Identifier(ref name) => { - let environment = &mut context.realm_mut().environment; - - if environment.has_binding(name.as_ref()) { + if context.has_binding(name.as_ref()) { // Binding already exists - environment - .set_mutable_binding(name.as_ref(), next_result.clone(), true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(name.as_ref(), next_result.clone(), true)?; } else { - environment - .create_mutable_binding( - name.as_ref().to_owned(), - true, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(name.as_ref(), next_result.clone()) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + name.as_ref().to_owned(), + true, + VariableScope::Function, + )?; + context.initialize_binding(name.as_ref(), next_result.clone())?; } } Node::VarDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; - if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-of loop can't have an initializer"); } - if environment.has_binding(var.name()) { - environment - .set_mutable_binding(var.name(), next_result, true) - .map_err(|e| e.to_error(context))?; + if context.has_binding(var.name()) { + context.set_mutable_binding(var.name(), next_result, true)?; } else { - environment - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Function, + )?; + context.initialize_binding(var.name(), next_result)?; } } _ => { @@ -152,24 +135,17 @@ impl Executable for ForOfLoop { }, Node::LetDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; - if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-of loop can't have an initializer"); } - environment - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + )?; + + context.initialize_binding(var.name(), next_result)?; } _ => { return context.throw_syntax_error( @@ -179,23 +155,16 @@ impl Executable for ForOfLoop { }, Node::ConstDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; - if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-of loop can't have an initializer"); } - environment - .create_immutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_immutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + )?; + context.initialize_binding(var.name(), next_result)?; } _ => { return context.throw_syntax_error( @@ -228,7 +197,7 @@ impl Executable for ForOfLoop { // Continue execution. } } - let _ = context.realm_mut().environment.pop(); + let _ = context.pop_environment(); } Ok(result) } diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index c58dd6a801..6f38bb22ed 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -342,11 +342,7 @@ impl Executable for Node { Node::Spread(ref spread) => spread.run(context), Node::This => { // Will either return `this` binding or undefined - context - .realm() - .environment - .get_this_binding() - .map_err(|e| e.to_error(context)) + context.get_this_binding() } Node::Try(ref try_node) => try_node.run(context), Node::Break(ref break_node) => break_node.run(context), diff --git a/boa/src/syntax/ast/node/operator/assign/mod.rs b/boa/src/syntax/ast/node/operator/assign/mod.rs index 0696ba81a3..0d362ec8d1 100644 --- a/boa/src/syntax/ast/node/operator/assign/mod.rs +++ b/boa/src/syntax/ast/node/operator/assign/mod.rs @@ -58,25 +58,16 @@ impl Executable for Assign { let val = self.rhs().run(context)?; match self.lhs() { Node::Identifier(ref name) => { - let environment = &mut context.realm_mut().environment; - - if environment.has_binding(name.as_ref()) { + if context.has_binding(name.as_ref()) { // Binding already exists - environment - .set_mutable_binding(name.as_ref(), val.clone(), true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(name.as_ref(), val.clone(), true)?; } else { - environment - .create_mutable_binding( - name.as_ref().to_owned(), - true, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(name.as_ref(), val.clone()) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + name.as_ref().to_owned(), + true, + VariableScope::Function, + )?; + context.initialize_binding(name.as_ref(), val.clone())?; } } Node::GetConstField(ref get_const_field) => { diff --git a/boa/src/syntax/ast/node/operator/bin_op/mod.rs b/boa/src/syntax/ast/node/operator/bin_op/mod.rs index f99e3ed28b..e20291353c 100644 --- a/boa/src/syntax/ast/node/operator/bin_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/bin_op/mod.rs @@ -205,18 +205,10 @@ impl Executable for BinOp { }), op::BinOp::Assign(op) => match self.lhs() { Node::Identifier(ref name) => { - let v_a = context - .realm() - .environment - .get_binding_value(name.as_ref()) - .map_err(|e| e.to_error(context))?; + let v_a = context.get_binding_value(name.as_ref())?; let value = Self::run_assign(op, v_a, self.rhs(), context)?; - context - .realm_mut() - .environment - .set_mutable_binding(name.as_ref(), value.clone(), true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(name.as_ref(), value.clone(), true)?; Ok(value) } Node::GetConstField(ref get_const_field) => { diff --git a/boa/src/syntax/ast/node/template/mod.rs b/boa/src/syntax/ast/node/template/mod.rs index ec8bb8a67d..f44fbd487c 100644 --- a/boa/src/syntax/ast/node/template/mod.rs +++ b/boa/src/syntax/ast/node/template/mod.rs @@ -128,10 +128,7 @@ impl Executable for TaggedTemplate { obj.get_field(field.to_property_key(context)?, context)?, ) } - _ => ( - context.global_object().clone().into(), - self.tag.run(context)?, - ), + _ => (context.global_object().into(), self.tag.run(context)?), }; let mut args = vec![template_object]; diff --git a/boa/src/syntax/ast/node/try_node/mod.rs b/boa/src/syntax/ast/node/try_node/mod.rs index ea90741a5e..cf56f56f0f 100644 --- a/boa/src/syntax/ast/node/try_node/mod.rs +++ b/boa/src/syntax/ast/node/try_node/mod.rs @@ -1,5 +1,8 @@ use crate::{ - environment::lexical_environment::{new_declarative_environment, VariableScope}, + environment::{ + declarative_environment_record::DeclarativeEnvironmentRecord, + lexical_environment::VariableScope, + }, exec::Executable, gc::{Finalize, Trace}, syntax::ast::node::{Block, Identifier, Node}, @@ -98,28 +101,23 @@ impl Executable for Try { |err| { if let Some(catch) = self.catch() { { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = context.get_current_environment(); + context.push_environment(DeclarativeEnvironmentRecord::new(Some(env))); if let Some(param) = catch.parameter() { - env.create_mutable_binding( + context.create_mutable_binding( param.to_owned(), false, VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - let env = &mut context.realm_mut().environment; - env.initialize_binding(param, err) - .map_err(|e| e.to_error(context))?; + )?; + context.initialize_binding(param, err)?; } } let res = catch.block().run(context); // pop the block env - let _ = context.realm_mut().environment.pop(); + let _ = context.pop_environment(); res } else {