Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: boa-dev/boa
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 01b71f4dd58710d0cef9c2b2d98273831a4b6d05
Choose a base ref
..
head repository: boa-dev/boa
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: b26077c337222cb6395ccc20af5472842d8faef5
Choose a head ref
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/eval/mod.rs
Original file line number Diff line number Diff line change
@@ -212,7 +212,7 @@ impl Eval {

// Poison the last parent function environment, because it may contain new declarations after/during eval.
if !strict {
context.vm.environments.poison_last_function();
context.vm.environments.poison_until_last_function();
}

// Set the compile time environment to the current running environment and save the number of current environments.
421 changes: 129 additions & 292 deletions boa_engine/src/environments/runtime.rs

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions boa_engine/src/vm/code_block.rs
Original file line number Diff line number Diff line change
@@ -1018,7 +1018,7 @@ impl JsObject {
context
.vm
.environments
.put_value(index, 0, class_object.into());
.put_declarative_value(index, 0, class_object.into());
last_env -= 1;
}

@@ -1030,7 +1030,7 @@ impl JsObject {
context
.vm
.environments
.put_value(index, 0, self.clone().into());
.put_declarative_value(index, 0, self.clone().into());
last_env -= 1;
}

@@ -1060,11 +1060,11 @@ impl JsObject {
&this_function_object,
&code.params,
args,
&env,
env.declarative_expect(),
context,
)
};
context.vm.environments.put_value(
context.vm.environments.put_declarative_value(
binding.environment_index(),
binding.binding_index(),
arguments_obj.into(),
@@ -1277,7 +1277,7 @@ impl JsObject {
context
.vm
.environments
.put_value(index, 0, self.clone().into());
.put_declarative_value(index, 0, self.clone().into());
last_env -= 1;
}

@@ -1306,11 +1306,11 @@ impl JsObject {
&this_function_object,
&code.params,
args,
&env,
env.declarative_expect(),
context,
)
};
context.vm.environments.put_value(
context.vm.environments.put_declarative_value(
binding.environment_index(),
binding.binding_index(),
arguments_obj.into(),
36 changes: 8 additions & 28 deletions boa_engine/src/vm/opcode/define/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
vm::{opcode::Operation, CompletionType},
Context, JsResult, JsString, JsValue,
Context, JsResult, JsValue,
};

pub(crate) mod class;
@@ -52,36 +52,16 @@ impl Operation for DefInitVar {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let value = context.vm.pop();
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
if binding_locator.is_silent() {
return Ok(CompletionType::Normal);
}
binding_locator.throw_mutate_immutable(context)?;

if binding_locator.is_global() {
if !context.put_value_if_global_poisoned(
binding_locator.name(),
&value,
context.vm.frame().code_block.strict,
)? {
let key = context
.interner()
.resolve_expect(binding_locator.name().sym())
.into_common::<JsString>(false);
context.global_object().set(
key,
value,
context.vm.frame().code_block.strict,
context,
)?;
}
} else {
context.vm.environments.put_value(
binding_locator.environment_index(),
binding_locator.binding_index(),
value,
);
}
context.find_runtime_binding(&mut binding_locator)?;

context.set_binding(binding_locator, value, context.vm.frame().code_block.strict)?;

Ok(CompletionType::Normal)
}
}
@@ -100,7 +80,7 @@ impl Operation for DefLet {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
context.vm.environments.put_value(
context.vm.environments.put_declarative_value(
binding_locator.environment_index(),
binding_locator.binding_index(),
JsValue::Undefined,
@@ -126,7 +106,7 @@ macro_rules! implement_declaratives {
let index = context.vm.read::<u32>();
let value = context.vm.pop();
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
context.vm.environments.put_value(
context.vm.environments.put_declarative_value(
binding_locator.environment_index(),
binding_locator.binding_index(),
value,
44 changes: 3 additions & 41 deletions boa_engine/src/vm/opcode/delete/mod.rs
Original file line number Diff line number Diff line change
@@ -76,50 +76,12 @@ impl Operation for DeleteName {

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
binding_locator.throw_mutate_immutable(context)?;

let deleted = if binding_locator.is_global()
&& !context
.vm
.environments
.binding_in_poisoned_environment(binding_locator.name())
{
let (found, deleted) =
context.delete_binding_from_object_environment(binding_locator.name())?;
if found {
context.vm.push(deleted);
return Ok(CompletionType::Normal);
}
context.find_runtime_binding(&mut binding_locator)?;

let key: JsString = context
.interner()
.resolve_expect(binding_locator.name().sym())
.into_common::<JsString>(false);
let deleted = context
.global_object()
.__delete__(&key.clone().into(), context)?;

if !deleted && context.vm.frame().code_block.strict {
return Err(JsNativeError::typ()
.with_message(format!(
"property `{}` is non-configurable and cannot be deleted",
key.to_std_string_escaped()
))
.into());
}
deleted
} else {
context
.vm
.environments
.get_value_optional(
binding_locator.environment_index(),
binding_locator.binding_index(),
binding_locator.name(),
)
.is_none()
};
let deleted = context.delete_binding(binding_locator)?;

context.vm.push(deleted);
Ok(CompletionType::Normal)
91 changes: 11 additions & 80 deletions boa_engine/src/vm/opcode/get/name.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::{
error::JsNativeError,
property::DescriptorKind,
vm::{opcode::Operation, CompletionType},
Context, JsResult, JsString, JsValue,
Context, JsResult,
};

/// `GetName` implements the Opcode Operation for `Opcode::GetName`
@@ -18,57 +17,16 @@ impl Operation for GetName {

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
binding_locator.throw_mutate_immutable(context)?;

let value = if binding_locator.is_global() {
if let Some(value) = context.get_value_if_global_poisoned(binding_locator.name())? {
value
} else {
let key: JsString = context
.interner()
.resolve_expect(binding_locator.name().sym())
.into_common(false);
match context.global_object().get_property(&key.clone().into()) {
Some(desc) => match desc.kind() {
DescriptorKind::Data {
value: Some(value), ..
} => value.clone(),
DescriptorKind::Accessor { get: Some(get), .. } if !get.is_undefined() => {
let get = get.clone();
get.call(&context.global_object().into(), &[], context)?
}
_ => {
return Err(JsNativeError::reference()
.with_message(format!(
"{} is not defined",
key.to_std_string_escaped()
))
.into())
}
},
_ => {
return Err(JsNativeError::reference()
.with_message(format!("{} is not defined", key.to_std_string_escaped()))
.into())
}
}
}
} else if let Some(value) = context.get_value_optional(
binding_locator.environment_index(),
binding_locator.binding_index(),
binding_locator.name(),
)? {
value
} else {
context.find_runtime_binding(&mut binding_locator)?;
let value = context.get_binding(binding_locator)?.ok_or_else(|| {
let name = context
.interner()
.resolve_expect(binding_locator.name().sym())
.to_string();
return Err(JsNativeError::reference()
.with_message(format!("{name} is not initialized"))
.into());
};
JsNativeError::reference().with_message(format!("{name} is not defined"))
})?;

context.vm.push(value);
Ok(CompletionType::Normal)
@@ -88,39 +46,12 @@ impl Operation for GetNameOrUndefined {

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
binding_locator.throw_mutate_immutable(context)?;
let value = if binding_locator.is_global() {
if let Some(value) = context.get_value_if_global_poisoned(binding_locator.name())? {
value
} else {
let key: JsString = context
.interner()
.resolve_expect(binding_locator.name().sym())
.into_common(false);
match context.global_object().get_property(&key.into()) {
Some(desc) => match desc.kind() {
DescriptorKind::Data {
value: Some(value), ..
} => value.clone(),
DescriptorKind::Accessor { get: Some(get), .. } if !get.is_undefined() => {
let get = get.clone();
get.call(&context.global_object().into(), &[], context)?
}
_ => JsValue::undefined(),
},
_ => JsValue::undefined(),
}
}
} else if let Some(value) = context.get_value_optional(
binding_locator.environment_index(),
binding_locator.binding_index(),
binding_locator.name(),
)? {
value
} else {
JsValue::undefined()
};

context.find_runtime_binding(&mut binding_locator)?;

let value = context.get_binding(binding_locator)?.unwrap_or_default();

context.vm.push(value);
Ok(CompletionType::Normal)
69 changes: 26 additions & 43 deletions boa_engine/src/vm/opcode/set/name.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::{
error::JsNativeError,
vm::{opcode::Operation, CompletionType},
Context, JsResult, JsString,
Context, JsNativeError, JsResult,
};

/// `SetName` implements the Opcode Operation for `Opcode::SetName`
@@ -17,59 +16,43 @@ impl Operation for SetName {

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
let value = context.vm.pop();
if binding_locator.is_silent() {
return Ok(CompletionType::Normal);
}
binding_locator.throw_mutate_immutable(context)?;

if binding_locator.is_global() {
if !context.put_value_if_global_poisoned(
binding_locator.name(),
&value,
context.vm.frame().code_block.strict,
)? {
let key: JsString = context
context.find_runtime_binding(&mut binding_locator)?;

if !context.is_initialized_binding(&binding_locator)? {
if binding_locator.is_global() && context.vm.frame().code_block.strict {
let key = context
.interner()
.resolve_expect(binding_locator.name().sym())
.into_common(false);
let exists = context
.global_object()
.has_own_property(key.clone(), context)?;
.to_string();

if !exists && context.vm.frame().code_block.strict {
return Err(JsNativeError::reference()
.with_message(format!(
"assignment to undeclared variable {}",
key.to_std_string_escaped()
))
.into());
}
return Err(JsNativeError::reference()
.with_message(format!(
"cannot assign to uninitialized global property `{key}`"
))
.into());
}

context.global_object().set(
key,
value,
context.vm.frame().code_block.strict,
context,
)?;
if !binding_locator.is_global() {
let key = context
.interner()
.resolve_expect(binding_locator.name().sym())
.to_string();

return Err(JsNativeError::reference()
.with_message(format!("cannot assign to uninitialized binding `{key}`"))
.into());
}
} else if !context.put_value_if_initialized(
binding_locator.environment_index(),
binding_locator.binding_index(),
binding_locator.name(),
value,
context.vm.frame().code_block.strict,
)? {
return Err(JsNativeError::reference()
.with_message(format!(
"cannot access '{}' before initialization",
context
.interner()
.resolve_expect(binding_locator.name().sym())
))
.into());
}

context.set_binding(binding_locator, value, context.vm.frame().code_block.strict)?;

Ok(CompletionType::Normal)
}
}