Browse Source

Fix super property access (#3026)

* Fix super property access

* Add better documentation to compiler
pull/3047/head
raskad 1 year ago committed by GitHub
parent
commit
86726f1238
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      boa_engine/src/bytecompiler/class.rs
  2. 3
      boa_engine/src/bytecompiler/declaration/declaration_pattern.rs
  3. 13
      boa_engine/src/bytecompiler/expression/assign.rs
  4. 5
      boa_engine/src/bytecompiler/expression/mod.rs
  5. 139
      boa_engine/src/bytecompiler/expression/object_literal.rs
  6. 11
      boa_engine/src/bytecompiler/expression/update.rs
  7. 27
      boa_engine/src/bytecompiler/mod.rs
  8. 4
      boa_engine/src/vm/code_block.rs
  9. 4
      boa_engine/src/vm/flowgraph/mod.rs
  10. 9
      boa_engine/src/vm/opcode/get/property.rs
  11. 19
      boa_engine/src/vm/opcode/mod.rs
  12. 31
      boa_engine/src/vm/opcode/set/home_object.rs
  13. 13
      boa_engine/src/vm/opcode/set/property.rs

4
boa_engine/src/bytecompiler/class.rs

@ -353,7 +353,7 @@ impl ByteCompiler<'_, '_> {
self.functions.push(code); self.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0); self.emit_u8(0);
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObjectClass);
self.emit(Opcode::Call, &[0]); self.emit(Opcode::Call, &[0]);
if let Some(name_index) = name_index { if let Some(name_index) = name_index {
self.emit(Opcode::DefineOwnPropertyByName, &[name_index]); self.emit(Opcode::DefineOwnPropertyByName, &[name_index]);
@ -401,7 +401,7 @@ impl ByteCompiler<'_, '_> {
self.functions.push(code); self.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0); self.emit_u8(0);
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObjectClass);
self.emit(Opcode::Call, &[0]); self.emit(Opcode::Call, &[0]);
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }

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

@ -35,6 +35,7 @@ impl ByteCompiler<'_, '_> {
name, name,
default_init, default_init,
} => { } => {
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
match name { match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
@ -106,6 +107,7 @@ impl ByteCompiler<'_, '_> {
access, access,
default_init, default_init,
} => { } => {
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
match name { match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
@ -145,6 +147,7 @@ impl ByteCompiler<'_, '_> {
pattern, pattern,
default_init, default_init,
} => { } => {
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
match name { match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {

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

@ -100,6 +100,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPropertyByName, &[index]); self.emit(Opcode::GetPropertyByName, &[index]);
if short_circuit { if short_circuit {
@ -119,11 +120,13 @@ impl ByteCompiler<'_, '_> {
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true); self.compile_expr(expr, true);
self.emit_opcode(Opcode::GetPropertyByValuePush); self.emit_opcode(Opcode::GetPropertyByValuePush);
if short_circuit { if short_circuit {
pop_count = 2; pop_count = 3;
early_exit = Some(self.emit_opcode_with_operand(opcode)); early_exit = Some(self.emit_opcode_with_operand(opcode));
self.compile_expr(assign.rhs(), true); self.compile_expr(assign.rhs(), true);
} else { } else {
@ -164,6 +167,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::This); self.emit_opcode(Opcode::This);
self.emit_opcode(Opcode::Swap); self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::This);
self.emit(Opcode::GetPropertyByName, &[index]); self.emit(Opcode::GetPropertyByName, &[index]);
if short_circuit { if short_circuit {
@ -183,6 +187,7 @@ impl ByteCompiler<'_, '_> {
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::This);
self.compile_expr(expr, true); self.compile_expr(expr, true);
self.emit_opcode(Opcode::GetPropertyByValuePush); self.emit_opcode(Opcode::GetPropertyByValuePush);
@ -195,7 +200,11 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(opcode); self.emit_opcode(opcode);
} }
self.emit(Opcode::SetPropertyByValue, &[]); self.emit_opcode(Opcode::This);
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(2);
self.emit_opcode(Opcode::SetPropertyByValue);
if !use_expr { if !use_expr {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }

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

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

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

@ -1,10 +1,11 @@
use crate::{ use crate::{
bytecompiler::{Access, ByteCompiler}, bytecompiler::{Access, ByteCompiler, FunctionSpec},
vm::Opcode, vm::Opcode,
}; };
use boa_ast::{ use boa_ast::{
expression::literal::ObjectLiteral, expression::literal::ObjectLiteral,
property::{MethodDefinition, PropertyDefinition, PropertyName}, property::{MethodDefinition, PropertyDefinition, PropertyName},
Expression,
}; };
use boa_interner::Sym; use boa_interner::Sym;
@ -47,97 +48,91 @@ impl ByteCompiler<'_, '_> {
MethodDefinition::Get(expr) => match name { MethodDefinition::Get(expr) => match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertyGetterByName, &[index]); self.emit(Opcode::SetPropertyGetterByName, &[index]);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true); self.compile_object_literal_computed_method(
self.emit_opcode(Opcode::ToPropertyKey); name_node,
self.emit_opcode(Opcode::Dup); expr.into(),
self.object_method(expr.into()); MethodKind::Get,
self.emit_opcode(Opcode::SetFunctionName); );
self.emit_u8(1);
self.emit_opcode(Opcode::SetPropertyGetterByValue);
} }
}, },
MethodDefinition::Set(expr) => match name { MethodDefinition::Set(expr) => match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertySetterByName, &[index]); self.emit(Opcode::SetPropertySetterByName, &[index]);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true); self.compile_object_literal_computed_method(
self.emit_opcode(Opcode::ToPropertyKey); name_node,
self.emit_opcode(Opcode::Dup); expr.into(),
self.object_method(expr.into()); MethodKind::Set,
self.emit_opcode(Opcode::SetFunctionName); );
self.emit_u8(2);
self.emit_opcode(Opcode::SetPropertySetterByValue);
} }
}, },
MethodDefinition::Ordinary(expr) => match name { MethodDefinition::Ordinary(expr) => match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[index]); self.emit(Opcode::DefineOwnPropertyByName, &[index]);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true); self.compile_object_literal_computed_method(
self.emit_opcode(Opcode::ToPropertyKey); name_node,
self.emit_opcode(Opcode::Dup); expr.into(),
self.object_method(expr.into()); MethodKind::Ordinary,
self.emit_opcode(Opcode::SetFunctionName); );
self.emit_u8(0);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
} }
}, },
MethodDefinition::Async(expr) => match name { MethodDefinition::Async(expr) => match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[index]); self.emit(Opcode::DefineOwnPropertyByName, &[index]);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true); self.compile_object_literal_computed_method(
self.emit_opcode(Opcode::ToPropertyKey); name_node,
self.emit_opcode(Opcode::Dup); expr.into(),
self.object_method(expr.into()); MethodKind::Ordinary,
self.emit_opcode(Opcode::SetFunctionName); );
self.emit_u8(0);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
} }
}, },
MethodDefinition::Generator(expr) => match name { MethodDefinition::Generator(expr) => match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[index]); self.emit(Opcode::DefineOwnPropertyByName, &[index]);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true); self.compile_object_literal_computed_method(
self.emit_opcode(Opcode::ToPropertyKey); name_node,
self.emit_opcode(Opcode::Dup); expr.into(),
self.object_method(expr.into()); MethodKind::Ordinary,
self.emit_opcode(Opcode::SetFunctionName); );
self.emit_u8(0);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
} }
}, },
MethodDefinition::AsyncGenerator(expr) => match name { MethodDefinition::AsyncGenerator(expr) => match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[index]); self.emit(Opcode::DefineOwnPropertyByName, &[index]);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true); self.compile_object_literal_computed_method(
self.emit_opcode(Opcode::ToPropertyKey); name_node,
self.emit_opcode(Opcode::Dup); expr.into(),
self.object_method(expr.into()); MethodKind::Ordinary,
self.emit_opcode(Opcode::SetFunctionName); );
self.emit_u8(0);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
} }
}, },
}, },
@ -157,4 +152,62 @@ impl ByteCompiler<'_, '_> {
self.emit(Opcode::Pop, &[]); self.emit(Opcode::Pop, &[]);
} }
} }
fn compile_object_literal_computed_method(
&mut self,
name: &Expression,
function: FunctionSpec<'_>,
kind: MethodKind,
) {
// stack: object, object
self.compile_expr(name, true);
// stack: object, object, name
self.emit_opcode(Opcode::ToPropertyKey);
// stack: object, object, ToPropertyKey(name)
self.emit_opcode(Opcode::Dup);
// stack: object, object, ToPropertyKey(name), ToPropertyKey(name)
self.object_method(function);
// stack: object, object, ToPropertyKey(name), ToPropertyKey(name), method
self.emit_opcode(Opcode::SetFunctionName);
match kind {
MethodKind::Get => self.emit_u8(1),
MethodKind::Set => self.emit_u8(2),
MethodKind::Ordinary => self.emit_u8(0),
}
// stack: object, object, ToPropertyKey(name), method
self.emit_opcode(Opcode::RotateLeft);
self.emit_u8(3);
// stack: object, ToPropertyKey(name), method, object
self.emit_opcode(Opcode::Swap);
// stack: object, ToPropertyKey(name), object, method
self.emit_opcode(Opcode::SetHomeObject);
// stack: object, ToPropertyKey(name), object, method
self.emit_opcode(Opcode::Swap);
// stack: object, ToPropertyKey(name), method, object
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(3);
// stack: object, object, ToPropertyKey(name), method
match kind {
MethodKind::Get => self.emit_opcode(Opcode::SetPropertyGetterByValue),
MethodKind::Set => self.emit_opcode(Opcode::SetPropertySetterByValue),
MethodKind::Ordinary => self.emit_opcode(Opcode::DefineOwnPropertyByValue),
}
}
}
#[derive(Debug, Clone, Copy)]
enum MethodKind {
Get,
Set,
Ordinary,
} }

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

@ -65,6 +65,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPropertyByName, &[index]); self.emit(Opcode::GetPropertyByName, &[index]);
self.emit_opcode(opcode); self.emit_opcode(opcode);
@ -81,13 +82,15 @@ impl ByteCompiler<'_, '_> {
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true); self.compile_expr(expr, true);
self.emit_opcode(Opcode::GetPropertyByValuePush); self.emit_opcode(Opcode::GetPropertyByValuePush);
self.emit_opcode(opcode); self.emit_opcode(opcode);
if post { if post {
self.emit_opcode(Opcode::RotateRight); self.emit_opcode(Opcode::RotateRight);
self.emit_u8(4); self.emit_u8(5);
} }
self.emit_opcode(Opcode::SetPropertyByValue); self.emit_opcode(Opcode::SetPropertyByValue);
@ -120,6 +123,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::This); self.emit_opcode(Opcode::This);
self.emit_opcode(Opcode::Swap); self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::This);
self.emit(Opcode::GetPropertyByName, &[index]); self.emit(Opcode::GetPropertyByName, &[index]);
self.emit_opcode(opcode); self.emit_opcode(opcode);
@ -136,6 +140,7 @@ impl ByteCompiler<'_, '_> {
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::This);
self.compile_expr(expr, true); self.compile_expr(expr, true);
self.emit_opcode(Opcode::GetPropertyByValuePush); self.emit_opcode(Opcode::GetPropertyByValuePush);
@ -145,6 +150,10 @@ impl ByteCompiler<'_, '_> {
self.emit_u8(2); self.emit_u8(2);
} }
self.emit_opcode(Opcode::This);
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(2);
self.emit_opcode(Opcode::SetPropertyByValue); self.emit_opcode(Opcode::SetPropertyByValue);
if post { if post {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);

27
boa_engine/src/bytecompiler/mod.rs

@ -571,12 +571,14 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Const(name) => { PropertyAccessField::Const(name) => {
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPropertyByName, &[index]); self.emit(Opcode::GetPropertyByName, &[index]);
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true); self.compile_expr(expr, true);
self.emit(Opcode::GetPropertyByValue, &[]); self.emit_opcode(Opcode::GetPropertyByValue);
} }
}, },
PropertyAccess::Private(access) => { PropertyAccess::Private(access) => {
@ -588,10 +590,12 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Const(field) => { PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into()); let index = self.get_or_insert_name((*field).into());
self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::This);
self.emit(Opcode::GetPropertyByName, &[index]); self.emit(Opcode::GetPropertyByName, &[index]);
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::This);
self.compile_expr(expr, true); self.compile_expr(expr, true);
self.emit_opcode(Opcode::GetPropertyByValue); self.emit_opcode(Opcode::GetPropertyByValue);
} }
@ -670,11 +674,12 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true); self.compile_expr(expr, true);
expr_fn(self, 2); expr_fn(self, 3);
self.emit(Opcode::SetPropertyByValue, &[]); self.emit_opcode(Opcode::SetPropertyByValue);
if !use_expr { if !use_expr {
self.emit(Opcode::Pop, &[]); self.emit_opcode(Opcode::Pop);
} }
} }
}, },
@ -699,12 +704,13 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
} }
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.emit(Opcode::Super, &[]); self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::This);
self.compile_expr(expr, true); self.compile_expr(expr, true);
expr_fn(self, 0); expr_fn(self, 1);
self.emit(Opcode::SetPropertyByValue, &[]); self.emit_opcode(Opcode::SetPropertyByValue);
if !use_expr { if !use_expr {
self.emit(Opcode::Pop, &[]); self.emit_opcode(Opcode::Pop);
} }
} }
}, },
@ -805,6 +811,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccess::Simple(access) => { PropertyAccess::Simple(access) => {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);
match access.field() { match access.field() {
PropertyAccessField::Const(field) => { PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into()); let index = self.get_or_insert_name((*field).into());
@ -825,6 +832,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccess::Super(access) => { PropertyAccess::Super(access) => {
self.emit_opcode(Opcode::This); self.emit_opcode(Opcode::This);
self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::This);
match access.field() { match access.field() {
PropertyAccessField::Const(field) => { PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into()); let index = self.get_or_insert_name((*field).into());
@ -909,6 +917,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
fn compile_optional_item_kind(&mut self, kind: &OptionalOperationKind) { fn compile_optional_item_kind(&mut self, kind: &OptionalOperationKind) {
match kind { match kind {
OptionalOperationKind::SimplePropertyAccess { field } => { OptionalOperationKind::SimplePropertyAccess { field } => {
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
match field { match field {
PropertyAccessField::Const(name) => { PropertyAccessField::Const(name) => {
@ -917,7 +926,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.compile_expr(expr, true); self.compile_expr(expr, true);
self.emit(Opcode::GetPropertyByValue, &[]); self.emit_opcode(Opcode::GetPropertyByValue);
} }
} }
self.emit_opcode(Opcode::RotateLeft); self.emit_opcode(Opcode::RotateLeft);

4
boa_engine/src/vm/code_block.rs

@ -455,6 +455,7 @@ impl CodeBlock {
| Opcode::PushClassPrototype | Opcode::PushClassPrototype
| Opcode::SetClassPrototype | Opcode::SetClassPrototype
| Opcode::SetHomeObject | Opcode::SetHomeObject
| Opcode::SetHomeObjectClass
| Opcode::Add | Opcode::Add
| Opcode::Sub | Opcode::Sub
| Opcode::Div | Opcode::Div
@ -609,8 +610,7 @@ impl CodeBlock {
| Opcode::Reserved47 | Opcode::Reserved47
| Opcode::Reserved48 | Opcode::Reserved48
| Opcode::Reserved49 | Opcode::Reserved49
| Opcode::Reserved50 | Opcode::Reserved50 => unreachable!("Reserved opcodes are unrechable"),
| Opcode::Reserved51 => unreachable!("Reserved opcodes are unrechable"),
} }
} }
} }

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

@ -534,6 +534,7 @@ impl CodeBlock {
| Opcode::PushClassPrototype | Opcode::PushClassPrototype
| Opcode::SetClassPrototype | Opcode::SetClassPrototype
| Opcode::SetHomeObject | Opcode::SetHomeObject
| Opcode::SetHomeObjectClass
| Opcode::Add | Opcode::Add
| Opcode::Sub | Opcode::Sub
| Opcode::Div | Opcode::Div
@ -708,8 +709,7 @@ impl CodeBlock {
| Opcode::Reserved47 | Opcode::Reserved47
| Opcode::Reserved48 | Opcode::Reserved48
| Opcode::Reserved49 | Opcode::Reserved49
| Opcode::Reserved50 | Opcode::Reserved50 => unreachable!("Reserved opcodes are unrechable"),
| Opcode::Reserved51 => unreachable!("Reserved opcodes are unrechable"),
} }
} }

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

@ -18,6 +18,7 @@ impl Operation for GetPropertyByName {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let receiver = context.vm.pop();
let value = context.vm.pop(); let value = context.vm.pop();
let object = if let Some(object) = value.as_object() { let object = if let Some(object) = value.as_object() {
object.clone() object.clone()
@ -28,7 +29,7 @@ impl Operation for GetPropertyByName {
let key = context.vm.frame().code_block.names[index as usize] let key = context.vm.frame().code_block.names[index as usize]
.clone() .clone()
.into(); .into();
let result = object.__get__(&key, value, context)?; let result = object.__get__(&key, receiver, context)?;
context.vm.push(result); context.vm.push(result);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
@ -48,6 +49,7 @@ impl Operation for GetPropertyByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let key = context.vm.pop(); let key = context.vm.pop();
let receiver = context.vm.pop();
let value = context.vm.pop(); let value = context.vm.pop();
let object = if let Some(object) = value.as_object() { let object = if let Some(object) = value.as_object() {
object.clone() object.clone()
@ -73,7 +75,7 @@ impl Operation for GetPropertyByValue {
} }
// Slow path: // Slow path:
let result = object.__get__(&key, value, context)?; let result = object.__get__(&key, receiver, context)?;
context.vm.push(result); context.vm.push(result);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
@ -118,6 +120,7 @@ impl Operation for GetPropertyByValuePush {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let key = context.vm.pop(); let key = context.vm.pop();
let receiver = context.vm.pop();
let value = context.vm.pop(); let value = context.vm.pop();
let object = if let Some(object) = value.as_object() { let object = if let Some(object) = value.as_object() {
object.clone() object.clone()
@ -144,7 +147,7 @@ impl Operation for GetPropertyByValuePush {
} }
// Slow path: // Slow path:
let result = object.__get__(&key, value, context)?; let result = object.__get__(&key, receiver, context)?;
context.vm.push(key); context.vm.push(key);
context.vm.push(result); context.vm.push(result);

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

@ -346,13 +346,20 @@ generate_impl! {
/// Stack: class, prototype **=>** class.prototype /// Stack: class, prototype **=>** class.prototype
SetClassPrototype, SetClassPrototype,
/// Set home object internal slot of a function object. /// Set home object internal slot of an object literal method.
/// ///
/// Operands: /// Operands:
/// ///
/// Stack: home, function **=>** home, function /// Stack: home, function **=>** home, function
SetHomeObject, SetHomeObject,
/// Set home object internal slot of a class method.
///
/// Operands:
///
/// Stack: home, function **=>** home, function
SetHomeObjectClass,
/// Set the prototype of an object if the value is an object or null. /// Set the prototype of an object if the value is an object or null.
/// ///
/// Operands: /// Operands:
@ -729,7 +736,7 @@ generate_impl! {
/// ///
/// Operands: name_index: `u32` /// Operands: name_index: `u32`
/// ///
/// Stack: object **=>** value /// Stack: object, receiver **=>** value
GetPropertyByName, GetPropertyByName,
/// Get a property method or undefined if the property is null or undefined. /// Get a property method or undefined if the property is null or undefined.
@ -746,7 +753,7 @@ generate_impl! {
/// ///
/// Operands: /// Operands:
/// ///
/// Stack: object, key **=>** value /// Stack: object, receiver, key **=>** value
GetPropertyByValue, GetPropertyByValue,
/// Get a property by value from an object an push the key and value on the stack. /// Get a property by value from an object an push the key and value on the stack.
@ -755,7 +762,7 @@ generate_impl! {
/// ///
/// Operands: /// Operands:
/// ///
/// Stack: object, key **=>** key, value /// Stack: object, receiver, key **=>** key, value
GetPropertyByValuePush, GetPropertyByValuePush,
/// Sets a property by name of an object. /// Sets a property by name of an object.
@ -810,7 +817,7 @@ generate_impl! {
/// ///
/// Operands: /// Operands:
/// ///
/// Stack: object, key, value **=>** value /// Stack: object, receiver, key, value **=>** value
SetPropertyByValue, SetPropertyByValue,
/// Defines a own property of an object by value. /// Defines a own property of an object by value.
@ -1819,8 +1826,6 @@ generate_impl! {
Reserved49 => Reserved, Reserved49 => Reserved,
/// Reserved [`Opcode`]. /// Reserved [`Opcode`].
Reserved50 => Reserved, Reserved50 => Reserved,
/// Reserved [`Opcode`].
Reserved51 => Reserved,
} }
} }

31
boa_engine/src/vm/opcode/set/home_object.rs

@ -14,6 +14,37 @@ impl Operation for SetHomeObject {
const NAME: &'static str = "SetHomeObject"; const NAME: &'static str = "SetHomeObject";
const INSTRUCTION: &'static str = "INST - SetHomeObject"; const INSTRUCTION: &'static str = "INST - SetHomeObject";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
let home = context.vm.pop();
{
let function_object = function.as_object().expect("must be object");
let home_object = home.as_object().expect("must be object");
let mut function_object_mut = function_object.borrow_mut();
let function_mut = function_object_mut
.as_function_mut()
.expect("must be function object");
function_mut.set_home_object(home_object.clone());
}
context.vm.push(home);
context.vm.push(function);
Ok(CompletionType::Normal)
}
}
/// `SetHomeObjectClass` implements the Opcode Operation for `Opcode::SetHomeObjectClass`
///
/// Operation:
/// - Set home object internal slot of a function object.
#[derive(Debug, Clone, Copy)]
pub(crate) struct SetHomeObjectClass;
impl Operation for SetHomeObjectClass {
const NAME: &'static str = "SetHomeObjectClass";
const INSTRUCTION: &'static str = "INST - SetHomeObjectClass";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop(); let function = context.vm.pop();
let home = context.vm.pop(); let home = context.vm.pop();

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

@ -59,6 +59,7 @@ impl Operation for SetPropertyByValue {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop(); let value = context.vm.pop();
let key = context.vm.pop(); let key = context.vm.pop();
let receiver = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let object = if let Some(object) = object.as_object() { let object = if let Some(object) = object.as_object() {
object.clone() object.clone()
@ -137,12 +138,12 @@ impl Operation for SetPropertyByValue {
} }
// Slow path: // Slow path:
object.set( let succeeded = object.__set__(key.clone(), value.clone(), receiver, context)?;
key, if !succeeded && context.vm.frame().code_block.strict() {
value.clone(), return Err(JsNativeError::typ()
context.vm.frame().code_block.strict(), .with_message(format!("cannot set non-writable property: {key}"))
context, .into());
)?; }
context.vm.stack.push(value); context.vm.stack.push(value);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
} }

Loading…
Cancel
Save