Browse Source

Fix value property assignment order

fix-value-prop-assignment-order
dependabot[bot] 1 year ago committed by jedel1043
parent
commit
c3e7b17c33
  1. 2
      boa_engine/src/bytecompiler/class.rs
  2. 48
      boa_engine/src/bytecompiler/declaration/declaration_pattern.rs
  3. 17
      boa_engine/src/bytecompiler/expression/assign.rs
  4. 5
      boa_engine/src/bytecompiler/expression/mod.rs
  5. 21
      boa_engine/src/bytecompiler/expression/object_literal.rs
  6. 14
      boa_engine/src/bytecompiler/expression/update.rs
  7. 34
      boa_engine/src/bytecompiler/mod.rs
  8. 8
      boa_engine/src/property/mod.rs
  9. 12
      boa_engine/src/vm/call_frame/mod.rs
  10. 2
      boa_engine/src/vm/code_block.rs
  11. 2
      boa_engine/src/vm/flowgraph/mod.rs
  12. 12
      boa_engine/src/vm/opcode/copy/mod.rs
  13. 20
      boa_engine/src/vm/opcode/define/class/getter.rs
  14. 20
      boa_engine/src/vm/opcode/define/class/method.rs
  15. 20
      boa_engine/src/vm/opcode/define/class/setter.rs
  16. 8
      boa_engine/src/vm/opcode/define/own_property.rs
  17. 10
      boa_engine/src/vm/opcode/delete/mod.rs
  18. 25
      boa_engine/src/vm/opcode/dup/mod.rs
  19. 69
      boa_engine/src/vm/opcode/get/property.rs
  20. 60
      boa_engine/src/vm/opcode/mod.rs
  21. 78
      boa_engine/src/vm/opcode/set/property.rs
  22. 2
      boa_engine/src/vm/opcode/to/mod.rs

2
boa_engine/src/bytecompiler/class.rs

@ -335,7 +335,7 @@ impl ByteCompiler<'_, '_> {
}
PropertyName::Computed(name) => {
self.compile_expr(name, true);
self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::ToPropertyKey);
None
}
};

48
boa_engine/src/bytecompiler/declaration/declaration_pattern.rs

@ -15,8 +15,6 @@ impl ByteCompiler<'_, '_> {
) {
match pattern {
Pattern::Object(pattern) => {
self.emit_opcode(Opcode::ValueNotNullOrUndefined);
self.emit_opcode(Opcode::RequireObjectCoercible);
let mut additional_excluded_keys_count = 0;
@ -35,19 +33,22 @@ impl ByteCompiler<'_, '_> {
name,
default_init,
} => {
self.emit_opcode(Opcode::Dup);
match name {
PropertyName::Literal(name) => {
self.emit_opcode(Opcode::Dup);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::GetPropertyByName, &[index]);
}
PropertyName::Computed(node) => {
self.emit_opcode(Opcode::Dup);
self.compile_expr(node, true);
self.emit_opcode(Opcode::ToPropertyKey);
if rest_exits {
self.emit_opcode(Opcode::GetPropertyByValuePush);
} else {
self.emit_opcode(Opcode::GetPropertyByValue);
self.emit_opcode(Opcode::DupKey);
}
self.emit_opcode(Opcode::GetPropertyByValue);
}
}
@ -60,7 +61,6 @@ impl ByteCompiler<'_, '_> {
self.emit_binding(def, *ident);
if rest_exits && name.computed().is_some() {
self.emit_opcode(Opcode::Swap);
additional_excluded_keys_count += 1;
}
}
@ -106,19 +106,22 @@ impl ByteCompiler<'_, '_> {
access,
default_init,
} => {
self.emit_opcode(Opcode::Dup);
match name {
PropertyName::Literal(name) => {
self.emit_opcode(Opcode::Dup);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::GetPropertyByName, &[index]);
}
PropertyName::Computed(node) => {
self.emit_opcode(Opcode::Dup);
self.compile_expr(node, true);
self.emit_opcode(Opcode::ToPropertyKey);
if rest_exits {
self.emit_opcode(Opcode::GetPropertyByValuePush);
} else {
self.emit_opcode(Opcode::GetPropertyByValue);
self.emit_opcode(Opcode::DupKey);
}
self.emit_opcode(Opcode::GetPropertyByValue);
}
}
@ -136,7 +139,6 @@ impl ByteCompiler<'_, '_> {
);
if rest_exits && name.computed().is_some() {
self.emit_opcode(Opcode::Swap);
additional_excluded_keys_count += 1;
}
}
@ -145,14 +147,18 @@ impl ByteCompiler<'_, '_> {
pattern,
default_init,
} => {
self.emit_opcode(Opcode::Dup);
match name {
PropertyName::Literal(name) => {
self.emit_opcode(Opcode::Dup);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::GetPropertyByName, &[index]);
}
PropertyName::Computed(node) => {
self.emit_opcode(Opcode::Dup);
self.compile_expr(node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::GetPropertyByValue);
}
}
@ -242,10 +248,10 @@ impl ByteCompiler<'_, '_> {
compiler.emit_opcode(Opcode::IteratorNextSetDone);
compiler.emit_opcode(unwrapping);
if level != 0 {
compiler.emit_opcode(Opcode::RotateLeft);
compiler.emit_u8(level + 3 + u8::from(with_done));
compiler.emit_opcode(Opcode::RotateLeft);
compiler.emit_u8(level + 3 + u8::from(with_done));
for _ in 0..level {
compiler.emit_opcode(Opcode::RotateLeft);
compiler.emit_u8(level + 3 + u8::from(with_done));
}
compiler.emit_opcode(Opcode::RotateLeft);
compiler.emit_u8(level + 1);
}
@ -285,10 +291,10 @@ impl ByteCompiler<'_, '_> {
}
compiler.emit_opcode(Opcode::IteratorToArray);
if level != 0 {
compiler.emit_opcode(Opcode::RotateLeft);
compiler.emit_u8(level + 3);
compiler.emit_opcode(Opcode::RotateLeft);
compiler.emit_u8(level + 3);
for _ in 0..level {
compiler.emit_opcode(Opcode::RotateLeft);
compiler.emit_u8(level + 3);
}
compiler.emit_opcode(Opcode::RotateLeft);
compiler.emit_u8(level + 1);
}

17
boa_engine/src/bytecompiler/expression/assign.rs

@ -108,11 +108,14 @@ impl ByteCompiler<'_, '_> {
PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::DupKey);
self.emit_opcode(Opcode::GetPropertyByValuePush);
self.emit_opcode(Opcode::GetPropertyByValue);
if short_circuit {
pop_count = 2;
pop_count = 1;
early_exit = Some(self.emit_opcode_with_operand(opcode));
self.compile_expr(assign.rhs(), true);
} else {
@ -172,11 +175,15 @@ impl ByteCompiler<'_, '_> {
PropertyAccessField::Expr(expr) => {
self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::DupKey);
self.emit_opcode(Opcode::GetPropertyByValue);
self.emit_opcode(Opcode::GetPropertyByValuePush);
if short_circuit {
pop_count = 2;
pop_count = 1;
early_exit = Some(self.emit_opcode_with_operand(opcode));
self.compile_expr(assign.rhs(), true);
} else {
@ -184,7 +191,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(opcode);
}
self.emit(Opcode::SetPropertyByValue, &[]);
self.emit_opcode(Opcode::SetPropertyByValue);
if !use_expr {
self.emit_opcode(Opcode::Pop);
}

5
boa_engine/src/bytecompiler/expression/mod.rs

@ -230,7 +230,7 @@ impl ByteCompiler<'_, '_> {
match template.tag() {
Expression::PropertyAccess(PropertyAccess::Simple(access)) => {
self.compile_expr(access.target(), true);
self.emit(Opcode::Dup, &[]);
self.emit_opcode(Opcode::Dup);
match access.field() {
PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into());
@ -238,7 +238,8 @@ impl ByteCompiler<'_, '_> {
}
PropertyAccessField::Expr(field) => {
self.compile_expr(field, true);
self.emit(Opcode::GetPropertyByValue, &[]);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::GetPropertyByValue);
}
}
}

21
boa_engine/src/bytecompiler/expression/object_literal.rs

@ -32,8 +32,9 @@ impl ByteCompiler<'_, '_> {
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
if expr.is_anonymous_function_definition() {
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::DupKey);
self.compile_expr(expr, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(0);
@ -53,7 +54,8 @@ impl ByteCompiler<'_, '_> {
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::DupKey);
self.function(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(1);
@ -69,7 +71,8 @@ impl ByteCompiler<'_, '_> {
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::DupKey);
self.function(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(2);
@ -85,7 +88,8 @@ impl ByteCompiler<'_, '_> {
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::DupKey);
self.function(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(0);
@ -101,7 +105,8 @@ impl ByteCompiler<'_, '_> {
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::DupKey);
self.function(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(0);
@ -117,7 +122,8 @@ impl ByteCompiler<'_, '_> {
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::DupKey);
self.function(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(0);
@ -133,7 +139,8 @@ impl ByteCompiler<'_, '_> {
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::DupKey);
self.function(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(0);

14
boa_engine/src/bytecompiler/expression/update.rs

@ -70,13 +70,16 @@ impl ByteCompiler<'_, '_> {
PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::DupKey);
self.emit_opcode(Opcode::GetPropertyByValuePush);
self.emit_opcode(Opcode::GetPropertyByValue);
self.emit_opcode(opcode);
if post {
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(4);
self.emit_u8(3);
}
self.emit_opcode(Opcode::SetPropertyByValue);
@ -125,13 +128,16 @@ impl ByteCompiler<'_, '_> {
PropertyAccessField::Expr(expr) => {
self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::DupKey);
self.emit_opcode(Opcode::GetPropertyByValuePush);
self.emit_opcode(Opcode::GetPropertyByValue);
self.emit_opcode(opcode);
if post {
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(2);
self.emit_u8(3);
}
self.emit_opcode(Opcode::SetPropertyByValue);

34
boa_engine/src/bytecompiler/mod.rs

@ -581,7 +581,9 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true);
self.compile_expr(expr, true);
self.emit(Opcode::GetPropertyByValue, &[]);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::GetPropertyByValue);
}
},
PropertyAccess::Private(access) => {
@ -598,6 +600,8 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Expr(expr) => {
self.emit_opcode(Opcode::Super);
self.compile_expr(expr, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::GetPropertyByValue);
}
},
@ -668,8 +672,12 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true);
self.compile_expr(expr, true);
expr_fn(self, 2);
self.emit(Opcode::SetPropertyByValue, &[]);
self.emit_opcode(Opcode::ToPropertyKey);
expr_fn(self, 1);
self.emit_opcode(Opcode::SetPropertyByValue);
if !use_expr {
self.emit(Opcode::Pop, &[]);
}
@ -688,7 +696,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Const(name) => {
self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::This);
expr_fn(self, 1);
expr_fn(self, 2);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertyByName, &[index]);
if !use_expr {
@ -698,8 +706,12 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Expr(expr) => {
self.emit(Opcode::Super, &[]);
self.compile_expr(expr, true);
expr_fn(self, 0);
self.emit(Opcode::SetPropertyByValue, &[]);
self.emit_opcode(Opcode::ToPropertyKey);
expr_fn(self, 1);
self.emit_opcode(Opcode::SetPropertyByValue);
if !use_expr {
self.emit(Opcode::Pop, &[]);
}
@ -722,10 +734,10 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true);
self.compile_expr(expr, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::DeletePropertyByValue);
}
},
// TODO: throw ReferenceError on super deletion.
PropertyAccess::Super(_) => self.emit_opcode(Opcode::DeleteSuperThrow),
PropertyAccess::Private(_) => {
unreachable!("deleting private properties should always throw early errors.")
@ -843,6 +855,9 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
}
PropertyAccessField::Expr(field) => {
self.compile_expr(field, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::GetPropertyByValue);
}
}
@ -863,6 +878,8 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
}
PropertyAccessField::Expr(expr) => {
self.compile_expr(expr, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::GetPropertyByValue);
}
}
@ -948,7 +965,8 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
}
PropertyAccessField::Expr(expr) => {
self.compile_expr(expr, true);
self.emit(Opcode::GetPropertyByValue, &[]);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::GetPropertyByValue);
}
}
self.emit_opcode(Opcode::RotateLeft);

8
boa_engine/src/property/mod.rs

@ -18,7 +18,7 @@
mod attribute;
use crate::{js_string, object::shape::slot::SlotAttributes, JsString, JsSymbol, JsValue};
use boa_gc::{Finalize, Trace};
use boa_gc::{empty_trace, Finalize, Trace};
use std::{fmt, iter::FusedIterator};
pub use attribute::Attribute;
@ -582,6 +582,12 @@ pub enum PropertyKey {
Index(u32),
}
// SAFETY: `PropertyKey` can only contain non-traceable types, making this
// empty implementation safe.
unsafe impl Trace for PropertyKey {
empty_trace!();
}
/// Utility function for parsing [`PropertyKey`].
fn parse_u32_index<I, T>(mut input: I) -> Option<u32>
where

12
boa_engine/src/vm/call_frame/mod.rs

@ -7,7 +7,7 @@ mod env_stack;
use crate::{
builtins::promise::PromiseCapability, environments::BindingLocator, object::JsObject,
vm::CodeBlock,
property::PropertyKey, vm::CodeBlock,
};
use boa_gc::{Finalize, Gc, Trace};
use thin_vec::ThinVec;
@ -43,8 +43,11 @@ pub struct CallFrame {
// Iterators and their `[[Done]]` flags that must be closed when an abrupt completion is thrown.
pub(crate) iterators: ThinVec<(JsObject, bool)>,
// The stack of bindings being updated.
pub(crate) binding_stack: Vec<BindingLocator>,
// Bindings being updated.
pub(crate) binding_stack: ThinVec<BindingLocator>,
// Property keys being accessed.
pub(crate) keys: ThinVec<PropertyKey>,
}
/// ---- `CallFrame` public API ----
@ -75,7 +78,8 @@ impl CallFrame {
promise_capability: None,
async_generator: None,
iterators: ThinVec::new(),
binding_stack: Vec::new(),
binding_stack: ThinVec::new(),
keys: ThinVec::new(),
}
}

2
boa_engine/src/vm/code_block.rs

@ -389,6 +389,7 @@ impl CodeBlock {
Opcode::Pop
| Opcode::PopIfThrown
| Opcode::Dup
| Opcode::DupKey
| Opcode::Swap
| Opcode::PushZero
| Opcode::PushOne
@ -436,7 +437,6 @@ impl CodeBlock {
| Opcode::Dec
| Opcode::DecPost
| Opcode::GetPropertyByValue
| Opcode::GetPropertyByValuePush
| Opcode::SetPropertyByValue
| Opcode::DefineOwnPropertyByValue
| Opcode::DefineClassStaticMethodByValue

2
boa_engine/src/vm/flowgraph/mod.rs

@ -465,6 +465,7 @@ impl CodeBlock {
Opcode::Pop
| Opcode::PopIfThrown
| Opcode::Dup
| Opcode::DupKey
| Opcode::Swap
| Opcode::PushZero
| Opcode::PushOne
@ -512,7 +513,6 @@ impl CodeBlock {
| Opcode::Dec
| Opcode::DecPost
| Opcode::GetPropertyByValue
| Opcode::GetPropertyByValuePush
| Opcode::SetPropertyByValue
| Opcode::DefineOwnPropertyByValue
| Opcode::DefineClassStaticMethodByValue

12
boa_engine/src/vm/opcode/copy/mod.rs

@ -29,11 +29,13 @@ impl Operation for CopyDataProperties {
let object = value.as_object().expect("not an object");
let source = context.vm.pop();
for _ in 0..excluded_key_count_computed {
let key = context.vm.pop();
excluded_keys.push(
key.to_property_key(context)
.expect("key must be property key"),
);
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
excluded_keys.push(key);
}
object.copy_data_properties(&source, excluded_keys, context)?;
context.vm.push(value);

20
boa_engine/src/vm/opcode/define/class/getter.rs

@ -129,12 +129,14 @@ impl Operation for DefineClassStaticGetterByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
let key = context.vm.pop();
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let class = context.vm.pop();
let class = class.as_object().expect("class must be object");
let key = key
.to_property_key(context)
.expect("property key must already be valid");
{
let function_object = function
.as_object()
@ -179,12 +181,14 @@ impl Operation for DefineClassGetterByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
let key = context.vm.pop();
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object");
let key = key
.to_property_key(context)
.expect("property key must already be valid");
{
let function_object = function
.as_object()

20
boa_engine/src/vm/opcode/define/class/method.rs

@ -121,12 +121,14 @@ impl Operation for DefineClassStaticMethodByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
let key = context.vm.pop();
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let class = context.vm.pop();
let class = class.as_object().expect("class must be object");
let key = key
.to_property_key(context)
.expect("property key must already be valid");
{
let function_object = function
.as_object()
@ -167,12 +169,14 @@ impl Operation for DefineClassMethodByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
let key = context.vm.pop();
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object");
let key = key
.to_property_key(context)
.expect("property key must already be valid");
{
let function_object = function
.as_object()

20
boa_engine/src/vm/opcode/define/class/setter.rs

@ -132,12 +132,14 @@ impl Operation for DefineClassStaticSetterByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
let key = context.vm.pop();
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let class = context.vm.pop();
let class = class.as_object().expect("class must be object");
let key = key
.to_property_key(context)
.expect("property key must already be valid");
{
let function_object = function
.as_object()
@ -184,12 +186,14 @@ impl Operation for DefineClassSetterByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
let key = context.vm.pop();
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object");
let key = key
.to_property_key(context)
.expect("property key must already be valid");
{
let function_object = function
.as_object()

8
boa_engine/src/vm/opcode/define/own_property.rs

@ -56,14 +56,18 @@ impl Operation for DefineOwnPropertyByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
let key = context.vm.pop();
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let object = context.vm.pop();
let object = if let Some(object) = object.as_object() {
object.clone()
} else {
object.to_object(context)?
};
let key = key.to_property_key(context)?;
let success = object.__define_own_property__(
&key,
PropertyDescriptor::builder()

10
boa_engine/src/vm/opcode/delete/mod.rs

@ -48,11 +48,15 @@ impl Operation for DeletePropertyByValue {
const INSTRUCTION: &'static str = "INST - DeletePropertyByValue";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let key_value = context.vm.pop();
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let value = context.vm.pop();
let object = value.to_object(context)?;
let property_key = key_value.to_property_key(context)?;
let result = object.__delete__(&property_key, context)?;
let result = object.__delete__(&key, context)?;
if !result && context.vm.frame().code_block.strict {
return Err(JsNativeError::typ()
.with_message("Cannot delete property")

25
boa_engine/src/vm/opcode/dup/mod.rs

@ -21,3 +21,28 @@ impl Operation for Dup {
Ok(CompletionType::Normal)
}
}
/// `DupKey` implements the Opcode Operation for `Opcode::DupKey`
///
/// Operation:
/// - Duplicates the top of the property keys stack
#[derive(Debug, Clone, Copy)]
pub(crate) struct DupKey;
impl Operation for DupKey {
const NAME: &'static str = "DupKey";
const INSTRUCTION: &'static str = "INST - DupKey";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let key = context
.vm
.frame_mut()
.keys
.last()
.expect("keys stack must not be empty")
.clone();
context.vm.frame_mut().keys.push(key);
Ok(CompletionType::Normal)
}
}

69
boa_engine/src/vm/opcode/get/property.rs

@ -20,11 +20,7 @@ impl Operation for GetPropertyByName {
let index = context.vm.read::<u32>();
let value = context.vm.pop();
let object = if let Some(object) = value.as_object() {
object.clone()
} else {
value.to_object(context)?
};
let object = value.to_object(context)?;
let name = context.vm.frame().code_block.names[index as usize];
let key: PropertyKey = context.interner().resolve_expect(name.sym()).utf16().into();
@ -47,15 +43,15 @@ impl Operation for GetPropertyByValue {
const INSTRUCTION: &'static str = "INST - GetPropertyByValue";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let key = context.vm.pop();
let value = context.vm.pop();
let object = if let Some(object) = value.as_object() {
object.clone()
} else {
value.to_object(context)?
};
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let key = key.to_property_key(context)?;
let value = context.vm.pop();
let object = value.to_object(context)?;
// Fast Path
if object.is_array() {
@ -105,50 +101,3 @@ impl Operation for GetMethod {
Ok(CompletionType::Normal)
}
}
/// `GetPropertyByValuePush` implements the Opcode Operation for `Opcode::GetPropertyByValuePush`
///
/// Operation:
/// - Get a property by value from an object an push the key and value on the stack.
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetPropertyByValuePush;
impl Operation for GetPropertyByValuePush {
const NAME: &'static str = "GetPropertyByValuePush";
const INSTRUCTION: &'static str = "INST - GetPropertyByValuePush";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let key = context.vm.pop();
let value = context.vm.pop();
let object = if let Some(object) = value.as_object() {
object.clone()
} else {
value.to_object(context)?
};
let key = key.to_property_key(context)?;
// Fast path:
if object.is_array() {
if let PropertyKey::Index(index) = &key {
let object_borrowed = object.borrow();
if let Some(element) = object_borrowed
.properties()
.dense_indexed_properties()
.and_then(|vec| vec.get(*index as usize))
{
context.vm.push(key);
context.vm.push(element.clone());
return Ok(CompletionType::Normal);
}
}
}
// Slow path:
let result = object.__get__(&key, value, context)?;
context.vm.push(key);
context.vm.push(result);
Ok(CompletionType::Normal)
}
}

60
boa_engine/src/vm/opcode/mod.rs

@ -621,7 +621,7 @@ generate_impl! {
///
/// Operands:
///
/// Stack: value **=>** (ToNumeric(value)), (value + 1)
/// Stack: value **=>** (value + 1), (ToNumeric(value))
IncPost,
/// Unary `--` operator.
@ -635,7 +635,7 @@ generate_impl! {
///
/// Operands:
///
/// Stack: value **=>** (ToNumeric(value)), (value - 1)
/// Stack: value **=>** (value - 1), (ToNumeric(value))
DecPost,
/// Declare and initialize a function argument.
@ -751,18 +751,10 @@ generate_impl! {
///
/// Operands:
///
/// Stack: object, key **=>** value
/// Stack: object **=>** value
/// Key stack: key **=>**
GetPropertyByValue,
/// Get a property by value from an object an push the key and value on the stack.
///
/// Like `object[key]`
///
/// Operands:
///
/// Stack: object, key **=>** key, value
GetPropertyByValuePush,
/// Sets a property by name of an object.
///
/// Like `object.name = value`
@ -815,28 +807,32 @@ generate_impl! {
///
/// Operands:
///
/// Stack: object, key, value **=>** value
/// Stack: object, value **=>** value
/// Key stack: key **=>**
SetPropertyByValue,
/// Defines a own property of an object by value.
///
/// Operands:
///
/// Stack: object, key, value **=>**
/// Stack: object, value **=>**
/// Key stack: key **=>**
DefineOwnPropertyByValue,
/// Defines a static class method by value.
///
/// Operands:
///
/// Stack: class, key, function **=>**
/// Stack: class, function **=>**
/// Key stack: key **=>**
DefineClassStaticMethodByValue,
/// Defines a class method by value.
///
/// Operands:
///
/// Stack: class_proto, key, function **=>**
/// Stack: class_proto, function **=>**
/// Key stack: key **=>**
DefineClassMethodByValue,
/// Sets a getter property by name of an object.
@ -872,7 +868,8 @@ generate_impl! {
///
/// Operands:
///
/// Stack: object, key, value **=>**
/// Stack: object, value **=>**
/// Key stack: key **=>**
SetPropertyGetterByValue,
/// Defines a static getter class method by value.
@ -881,7 +878,8 @@ generate_impl! {
///
/// Operands:
///
/// Stack: class, key, function **=>**
/// Stack: class, function **=>**
/// Key stack: key **=>**
DefineClassStaticGetterByValue,
/// Defines a getter class method by value.
@ -890,7 +888,8 @@ generate_impl! {
///
/// Operands:
///
/// Stack: class_proto, key, function **=>**
/// Stack: class_proto, function **=>**
/// Key stack: key **=>**
DefineClassGetterByValue,
/// Sets a setter property by name of an object.
@ -926,7 +925,8 @@ generate_impl! {
///
/// Operands:
///
/// Stack: object, key, value **=>**
/// Stack: object, value **=>**
/// Key stack: key **=>**
SetPropertySetterByValue,
/// Defines a static setter class method by value.
@ -935,7 +935,8 @@ generate_impl! {
///
/// Operands:
///
/// Stack: class, key, function **=>**
/// Stack: class, function **=>**
/// Key stack: key **=>**
DefineClassStaticSetterByValue,
/// Defines a setter class method by value.
@ -944,7 +945,8 @@ generate_impl! {
///
/// Operands:
///
/// Stack: class_proto, key, function **=>**
/// Stack: class_proto, function **=>**
/// Key stack: key **=>**
DefineClassSetterByValue,
/// Set the value of a private property of an object by it's name.
@ -1051,7 +1053,8 @@ generate_impl! {
///
/// Operands:
///
/// Stack: object, key **=>**
/// Stack: object **=>**
/// Key stack: key **=>**
DeletePropertyByValue,
/// Throws an error when trying to delete a property of `super`
@ -1072,9 +1075,18 @@ generate_impl! {
///
/// Operands:
///
/// Stack: value **=>** key
/// Stack: value **=>**
///
/// Key stack: **=>** key
ToPropertyKey,
/// Duplicates the top of the property keys stack.
///
/// Operands:
///
/// Key stack: key **=>** key, key
DupKey,
/// Unconditional jump to address.
///
/// Operands: address: `u32`

78
boa_engine/src/vm/opcode/set/property.rs

@ -4,7 +4,7 @@ use crate::{
builtins::function::set_function_name,
property::{PropertyDescriptor, PropertyKey},
vm::{opcode::Operation, CompletionType},
Context, JsNativeError, JsResult, JsString, JsValue,
Context, JsNativeError, JsResult, JsString,
};
/// `SetPropertyByName` implements the Opcode Operation for `Opcode::SetPropertyByName`
@ -23,12 +23,7 @@ impl Operation for SetPropertyByName {
let value = context.vm.pop();
let receiver = context.vm.pop();
let object = context.vm.pop();
let object = if let Some(object) = object.as_object() {
object.clone()
} else {
object.to_object(context)?
};
let object = context.vm.pop().to_object(context)?;
let name = context.vm.frame().code_block.names[index as usize];
let name: PropertyKey = context.interner().resolve_expect(name.sym()).utf16().into();
@ -57,15 +52,14 @@ impl Operation for SetPropertyByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
let key = context.vm.pop();
let object = context.vm.pop();
let object = if let Some(object) = object.as_object() {
object.clone()
} else {
object.to_object(context)?
};
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let key = key.to_property_key(context)?;
let object = context.vm.pop().to_object(context)?;
// Fast Path:
'fast_path: {
@ -201,17 +195,20 @@ impl Operation for SetPropertyGetterByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
let key = context.vm.pop();
let object = context.vm.pop();
let object = object.to_object(context)?;
let name = key.to_property_key(context)?;
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let object = context.vm.pop().to_object(context)?;
let set = object
.__get_own_property__(&name, context)?
.__get_own_property__(&key, context)?
.as_ref()
.and_then(PropertyDescriptor::set)
.cloned();
object.__define_own_property__(
&name,
&key,
PropertyDescriptor::builder()
.maybe_get(Some(value))
.maybe_set(set)
@ -278,17 +275,20 @@ impl Operation for SetPropertySetterByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
let key = context.vm.pop();
let object = context.vm.pop();
let object = object.to_object(context)?;
let name = key.to_property_key(context)?;
let key = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let object = context.vm.pop().to_object(context)?;
let get = object
.__get_own_property__(&name, context)?
.__get_own_property__(&key, context)?
.as_ref()
.and_then(PropertyDescriptor::get)
.cloned();
object.__define_own_property__(
&name,
&key,
PropertyDescriptor::builder()
.maybe_set(Some(value))
.maybe_get(get)
@ -314,14 +314,13 @@ impl Operation for SetFunctionName {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let prefix = context.vm.read::<u8>();
let function = context.vm.pop();
let name = context.vm.pop();
let name = match name {
JsValue::String(name) => name.into(),
JsValue::Symbol(name) => name.into(),
_ => unreachable!(),
};
let function = context.vm.pop().to_object(context)?;
let name = context
.vm
.frame_mut()
.keys
.pop()
.expect("property key should have been pushed");
let prefix = match prefix {
1 => Some(JsString::from("get")),
@ -329,14 +328,9 @@ impl Operation for SetFunctionName {
_ => None,
};
set_function_name(
function.as_object().expect("function is not an object"),
&name,
prefix,
context,
);
set_function_name(&function, &name, prefix, context);
context.vm.stack.push(function);
context.vm.push(function);
Ok(CompletionType::Normal)
}
}

2
boa_engine/src/vm/opcode/to/mod.rs

@ -35,7 +35,7 @@ impl Operation for ToPropertyKey {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
let key = value.to_property_key(context)?;
context.vm.push(key);
context.vm.frame_mut().keys.push(key);
Ok(CompletionType::Normal)
}
}

Loading…
Cancel
Save