Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make environment methods take &mut Context #1131

Merged
merged 9 commits into from
May 10, 2021
3 changes: 1 addition & 2 deletions boa/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 5 additions & 4 deletions boa/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand All @@ -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");
}

Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/global_this/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl BuiltIn for GlobalThis {

(
Self::NAME,
context.global_object().clone().into(),
context.global_object().into(),
Self::attribute(),
)
}
Expand Down
7 changes: 1 addition & 6 deletions boa/src/builtins/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
29 changes: 8 additions & 21 deletions boa/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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(())
}
Expand All @@ -574,10 +564,7 @@ impl Context {
pub(crate) fn set_value(&mut self, node: &Node, value: Value) -> Result<Value> {
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
Expand Down Expand Up @@ -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(())
}

Expand All @@ -643,7 +630,7 @@ impl Context {
V: Into<Value>,
{
let property = DataDescriptor::new(value, attribute);
self.global_object().clone().insert(key, property);
self.global_object().insert(key, property);
}

/// Evaluates the given code.
Expand Down
86 changes: 49 additions & 37 deletions boa/src/environment/declarative_environment_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -33,10 +34,23 @@ pub struct DeclarativeEnvironmentRecordBinding {
/// declarations contained within its scope.
#[derive(Debug, Trace, Finalize, Clone)]
pub struct DeclarativeEnvironmentRecord {
pub env_rec: FxHashMap<String, DeclarativeEnvironmentRecordBinding>,
pub env_rec: FxHashMap<Box<str>, DeclarativeEnvironmentRecordBinding>,
pub outer_env: Option<Environment>,
}

impl DeclarativeEnvironmentRecord {
#[allow(clippy::new_ret_no_self)]
pub fn new(env: Option<Environment>) -> 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)
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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);
Expand All @@ -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(());
}

Expand All @@ -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
)));
Expand All @@ -139,15 +161,12 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
Ok(())
}

fn get_binding_value(&self, name: &str, _strict: bool) -> Result<Value, ErrorKind> {
fn get_binding_value(&self, name: &str, _strict: bool, context: &mut Context) -> Result<Value> {
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);
Expand All @@ -172,16 +191,16 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
false
}

fn get_this_binding(&self) -> Result<Value, ErrorKind> {
fn get_this_binding(&self, _context: &mut Context) -> Result<Value> {
Ok(Value::undefined())
}

fn has_super_binding(&self) -> bool {
false
}

fn with_base_object(&self) -> Value {
Value::undefined()
fn with_base_object(&self) -> Option<GcObject> {
None
}

fn get_outer_environment_ref(&self) -> Option<&Environment> {
Expand All @@ -195,11 +214,4 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
fn get_environment_type(&self) -> EnvironmentType {
EnvironmentType::Declarative
}

fn get_global_object(&self) -> Option<Value> {
match &self.outer_env {
Some(outer) => outer.borrow().get_global_object(),
None => None,
}
}
}
Loading