Browse Source

Varying length instruction operands (#3253)

* Implement varying length operands

* Apply review

* Apply review
pull/3328/head
Haled Odat 1 year ago committed by GitHub
parent
commit
332fd658a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 98
      boa_engine/src/bytecompiler/class.rs
  2. 24
      boa_engine/src/bytecompiler/declaration/declaration_pattern.rs
  3. 26
      boa_engine/src/bytecompiler/declarations.rs
  4. 20
      boa_engine/src/bytecompiler/expression/assign.rs
  5. 7
      boa_engine/src/bytecompiler/expression/binary.rs
  6. 23
      boa_engine/src/bytecompiler/expression/mod.rs
  7. 18
      boa_engine/src/bytecompiler/expression/object_literal.rs
  8. 4
      boa_engine/src/bytecompiler/expression/unary.rs
  9. 20
      boa_engine/src/bytecompiler/expression/update.rs
  10. 173
      boa_engine/src/bytecompiler/mod.rs
  11. 8
      boa_engine/src/bytecompiler/statement/loop.rs
  12. 2
      boa_engine/src/bytecompiler/utils.rs
  13. 4
      boa_engine/src/module/source.rs
  14. 109
      boa_engine/src/vm/code_block.rs
  15. 27
      boa_engine/src/vm/flowgraph/mod.rs
  16. 22
      boa_engine/src/vm/mod.rs
  17. 30
      boa_engine/src/vm/opcode/binary_ops/mod.rs
  18. 60
      boa_engine/src/vm/opcode/call/mod.rs
  19. 30
      boa_engine/src/vm/opcode/concat/mod.rs
  20. 30
      boa_engine/src/vm/opcode/control_flow/throw.rs
  21. 38
      boa_engine/src/vm/opcode/copy/mod.rs
  22. 64
      boa_engine/src/vm/opcode/define/class/getter.rs
  23. 64
      boa_engine/src/vm/opcode/define/class/method.rs
  24. 64
      boa_engine/src/vm/opcode/define/class/setter.rs
  25. 95
      boa_engine/src/vm/opcode/define/mod.rs
  26. 30
      boa_engine/src/vm/opcode/define/own_property.rs
  27. 62
      boa_engine/src/vm/opcode/delete/mod.rs
  28. 30
      boa_engine/src/vm/opcode/environment/mod.rs
  29. 122
      boa_engine/src/vm/opcode/get/function.rs
  30. 54
      boa_engine/src/vm/opcode/get/generator.rs
  31. 116
      boa_engine/src/vm/opcode/get/name.rs
  32. 30
      boa_engine/src/vm/opcode/get/private.rs
  33. 60
      boa_engine/src/vm/opcode/get/property.rs
  34. 325
      boa_engine/src/vm/opcode/mod.rs
  35. 39
      boa_engine/src/vm/opcode/modifier.rs
  36. 30
      boa_engine/src/vm/opcode/new/mod.rs
  37. 8
      boa_engine/src/vm/opcode/nop/mod.rs
  38. 31
      boa_engine/src/vm/opcode/push/class/field.rs
  39. 93
      boa_engine/src/vm/opcode/push/class/private.rs
  40. 25
      boa_engine/src/vm/opcode/push/literal.rs
  41. 60
      boa_engine/src/vm/opcode/set/name.rs
  42. 154
      boa_engine/src/vm/opcode/set/private.rs
  43. 97
      boa_engine/src/vm/opcode/set/property.rs
  44. 34
      boa_engine/src/vm/opcode/templates/mod.rs

98
boa_engine/src/bytecompiler/class.rs

@ -80,7 +80,7 @@ impl ByteCompiler<'_, '_> {
self.functions.push(code);
self.emit(
Opcode::GetFunction,
&[Operand::U32(index), Operand::Bool(false)],
&[Operand::Varying(index), Operand::Bool(false)],
);
let class_env: Option<super::Label> = match class.name() {
@ -129,9 +129,9 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(
self.emit_with_varying_operand(
Opcode::DefineClassStaticGetterByName,
&[Operand::U32(index)],
index,
);
}
PropertyName::Computed(name_node) => {
@ -145,9 +145,9 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(
self.emit_with_varying_operand(
Opcode::DefineClassStaticSetterByName,
&[Operand::U32(index)],
index,
);
}
PropertyName::Computed(name_node) => {
@ -161,9 +161,9 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(
self.emit_with_varying_operand(
Opcode::DefineClassStaticMethodByName,
&[Operand::U32(index)],
index,
);
}
PropertyName::Computed(name_node) => {
@ -177,9 +177,9 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(
self.emit_with_varying_operand(
Opcode::DefineClassStaticMethodByName,
&[Operand::U32(index)],
index,
);
}
PropertyName::Computed(name_node) => {
@ -193,9 +193,9 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(
self.emit_with_varying_operand(
Opcode::DefineClassStaticMethodByName,
&[Operand::U32(index)],
index,
);
}
PropertyName::Computed(name_node) => {
@ -209,9 +209,9 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(
self.emit_with_varying_operand(
Opcode::DefineClassStaticMethodByName,
&[Operand::U32(index)],
index,
);
}
PropertyName::Computed(name_node) => {
@ -230,32 +230,32 @@ impl ByteCompiler<'_, '_> {
MethodDefinition::Get(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::SetPrivateGetter, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPrivateGetter, index);
}
MethodDefinition::Set(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::SetPrivateSetter, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPrivateSetter, index);
}
MethodDefinition::Ordinary(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::SetPrivateMethod, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPrivateMethod, index);
}
MethodDefinition::Async(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::SetPrivateMethod, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPrivateMethod, index);
}
MethodDefinition::Generator(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::SetPrivateMethod, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPrivateMethod, index);
}
MethodDefinition::AsyncGenerator(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::SetPrivateMethod, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPrivateMethod, index);
}
}
}
@ -299,7 +299,7 @@ impl ByteCompiler<'_, '_> {
self.functions.push(code);
self.emit(
Opcode::GetFunction,
&[Operand::U32(index), Operand::Bool(false)],
&[Operand::Varying(index), Operand::Bool(false)],
);
self.emit_opcode(Opcode::PushClassField);
}
@ -334,9 +334,9 @@ impl ByteCompiler<'_, '_> {
self.functions.push(code);
self.emit(
Opcode::GetFunction,
&[Operand::U32(index), Operand::Bool(false)],
&[Operand::Varying(index), Operand::Bool(false)],
);
self.emit(Opcode::PushClassFieldPrivate, &[Operand::U32(name_index)]);
self.emit_with_varying_operand(Opcode::PushClassFieldPrivate, name_index);
}
ClassElement::StaticFieldDefinition(name, field) => {
self.emit_opcode(Opcode::Dup);
@ -379,12 +379,12 @@ impl ByteCompiler<'_, '_> {
self.functions.push(code);
self.emit(
Opcode::GetFunction,
&[Operand::U32(index), Operand::Bool(false)],
&[Operand::Varying(index), Operand::Bool(false)],
);
self.emit_opcode(Opcode::SetHomeObjectClass);
self.emit(Opcode::Call, &[Operand::U32(0)]);
self.emit_with_varying_operand(Opcode::Call, 0);
if let Some(name_index) = name_index {
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(name_index)]);
self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, name_index);
} else {
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
}
@ -397,7 +397,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::PushUndefined);
}
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::DefinePrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefinePrivateField, index);
}
ClassElement::StaticBlock(body) => {
self.emit_opcode(Opcode::Dup);
@ -429,10 +429,10 @@ impl ByteCompiler<'_, '_> {
self.functions.push(code);
self.emit(
Opcode::GetFunction,
&[Operand::U32(index), Operand::Bool(false)],
&[Operand::Varying(index), Operand::Bool(false)],
);
self.emit_opcode(Opcode::SetHomeObjectClass);
self.emit(Opcode::Call, &[Operand::U32(0)]);
self.emit_with_varying_operand(Opcode::Call, 0);
self.emit_opcode(Opcode::Pop);
}
// TODO: set names for private methods
@ -442,32 +442,32 @@ impl ByteCompiler<'_, '_> {
MethodDefinition::Get(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::PushClassPrivateGetter, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::PushClassPrivateGetter, index);
}
MethodDefinition::Set(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::PushClassPrivateSetter, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::PushClassPrivateSetter, index);
}
MethodDefinition::Ordinary(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::PushClassPrivateMethod, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index);
}
MethodDefinition::Async(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::PushClassPrivateMethod, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index);
}
MethodDefinition::Generator(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::PushClassPrivateMethod, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index);
}
MethodDefinition::AsyncGenerator(expr) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_private_name(*name);
self.emit(Opcode::PushClassPrivateMethod, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index);
}
}
}
@ -487,7 +487,10 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineClassGetterByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(
Opcode::DefineClassGetterByName,
index,
);
}
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
@ -500,7 +503,10 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineClassSetterByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(
Opcode::DefineClassSetterByName,
index,
);
}
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
@ -513,7 +519,10 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineClassMethodByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(
Opcode::DefineClassMethodByName,
index,
);
}
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
@ -526,7 +535,10 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineClassMethodByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(
Opcode::DefineClassMethodByName,
index,
);
}
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
@ -539,7 +551,10 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineClassMethodByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(
Opcode::DefineClassMethodByName,
index,
);
}
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);
@ -552,7 +567,10 @@ impl ByteCompiler<'_, '_> {
PropertyName::Literal(name) => {
self.method(expr.into(), class_name);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineClassMethodByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(
Opcode::DefineClassMethodByName,
index,
);
}
PropertyName::Computed(name_node) => {
self.compile_expr(name_node, true);

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

@ -40,7 +40,10 @@ impl ByteCompiler<'_, '_> {
match name {
PropertyName::Literal(name) => {
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(
Opcode::GetPropertyByName,
index,
);
}
PropertyName::Computed(node) => {
self.compile_expr(node, true);
@ -81,8 +84,8 @@ impl ByteCompiler<'_, '_> {
self.emit(
Opcode::CopyDataProperties,
&[
Operand::U32(excluded_keys.len() as u32),
Operand::U32(additional_excluded_keys_count),
Operand::Varying(excluded_keys.len() as u32),
Operand::Varying(additional_excluded_keys_count),
],
);
self.emit_binding(def, *ident);
@ -100,7 +103,10 @@ impl ByteCompiler<'_, '_> {
}
self.emit(
Opcode::CopyDataProperties,
&[Operand::U32(excluded_keys.len() as u32), Operand::U32(0)],
&[
Operand::Varying(excluded_keys.len() as u32),
Operand::Varying(0),
],
);
self.access_set(
Access::Property { access },
@ -118,7 +124,10 @@ impl ByteCompiler<'_, '_> {
match name {
PropertyName::Literal(name) => {
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(
Opcode::GetPropertyByName,
index,
);
}
PropertyName::Computed(node) => {
self.compile_expr(node, true);
@ -158,7 +167,10 @@ impl ByteCompiler<'_, '_> {
match name {
PropertyName::Literal(name) => {
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(
Opcode::GetPropertyByName,
index,
);
}
PropertyName::Computed(node) => {
self.compile_expr(node, true);

26
boa_engine/src/bytecompiler/declarations.rs

@ -572,7 +572,7 @@ impl ByteCompiler<'_, '_> {
let binding = self.initialize_mutable_binding(f, true);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefInitVar, index);
}
}
@ -719,18 +719,18 @@ impl ByteCompiler<'_, '_> {
let index = self.functions.len() as u32;
self.functions.push(code);
if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator {
self.emit(Opcode::GetGenerator, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async {
self.emit(
Opcode::GetFunctionAsync,
&[Operand::U32(index), Operand::Bool(false)],
&[Operand::Varying(index), Operand::Bool(false)],
);
} else {
self.emit(
Opcode::GetFunction,
&[Operand::U32(index), Operand::Bool(false)],
&[Operand::Varying(index), Operand::Bool(false)],
);
}
@ -744,11 +744,11 @@ impl ByteCompiler<'_, '_> {
match self.set_mutable_binding(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetName, index);
}
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index);
}
Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop);
@ -761,7 +761,7 @@ impl ByteCompiler<'_, '_> {
self.create_mutable_binding(name, !strict);
let binding = self.initialize_mutable_binding(name, !strict);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefInitVar, index);
}
}
}
@ -787,7 +787,7 @@ impl ByteCompiler<'_, '_> {
let binding = self.initialize_mutable_binding(name, !strict);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefInitVar, index);
}
}
}
@ -1056,14 +1056,14 @@ impl ByteCompiler<'_, '_> {
// a. Let initialValue be ! env.GetBindingValue(n, false).
let binding = self.get_binding_value(n);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::GetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetName, index);
}
// 5. Perform ! varEnv.InitializeBinding(n, initialValue).
let binding = self.initialize_mutable_binding(n, true);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefInitVar, index);
// 6. NOTE: A var with the same name as a formal parameter initially has
// the same value as the corresponding initialized parameter.
@ -1090,7 +1090,7 @@ impl ByteCompiler<'_, '_> {
let binding = self.initialize_mutable_binding(n, true);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefInitVar, index);
}
}
@ -1122,7 +1122,7 @@ impl ByteCompiler<'_, '_> {
let binding = self.initialize_mutable_binding(f, true);
let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined);
self.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefInitVar, index);
// c. Append F to instantiatedVarNames.
instantiated_var_names.push(f);

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

@ -60,9 +60,9 @@ impl ByteCompiler<'_, '_> {
let lex = self.current_environment.is_lex_binding(name);
if lex {
self.emit(Opcode::GetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetName, index);
} else {
self.emit(Opcode::GetNameAndLocator, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetNameAndLocator, index);
}
if short_circuit {
@ -79,11 +79,11 @@ impl ByteCompiler<'_, '_> {
match self.set_mutable_binding(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetName, index);
}
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index);
}
Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop);
@ -102,7 +102,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
if short_circuit {
pop_count = 2;
early_exit = Some(self.emit_opcode_with_operand(opcode));
@ -112,7 +112,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(opcode);
}
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if !use_expr {
self.emit_opcode(Opcode::Pop);
}
@ -145,7 +145,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPrivateField, index);
if short_circuit {
pop_count = 1;
early_exit = Some(self.emit_opcode_with_operand(opcode));
@ -155,7 +155,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(opcode);
}
self.emit(Opcode::SetPrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPrivateField, index);
if !use_expr {
self.emit_opcode(Opcode::Pop);
}
@ -169,7 +169,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::This);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
if short_circuit {
pop_count = 2;
early_exit = Some(self.emit_opcode_with_operand(opcode));
@ -179,7 +179,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(opcode);
}
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if !use_expr {
self.emit_opcode(Opcode::Pop);
}

7
boa_engine/src/bytecompiler/expression/binary.rs

@ -3,10 +3,7 @@ use boa_ast::expression::operator::{
Binary, BinaryInPrivate,
};
use crate::{
bytecompiler::{ByteCompiler, Operand},
vm::Opcode,
};
use crate::{bytecompiler::ByteCompiler, vm::Opcode};
impl ByteCompiler<'_, '_> {
pub(crate) fn compile_binary(&mut self, binary: &Binary, use_expr: bool) {
@ -100,7 +97,7 @@ impl ByteCompiler<'_, '_> {
pub(crate) fn compile_binary_in_private(&mut self, binary: &BinaryInPrivate, use_expr: bool) {
let index = self.get_or_insert_private_name(*binary.lhs());
self.compile_expr(binary.rhs(), true);
self.emit(Opcode::InPrivate, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::InPrivate, index);
if !use_expr {
self.emit_opcode(Opcode::Pop);

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

@ -66,9 +66,9 @@ impl ByteCompiler<'_, '_> {
}
}
self.emit(
self.emit_with_varying_operand(
Opcode::ConcatToString,
&[Operand::U32(template_literal.elements().len() as u32)],
template_literal.elements().len() as u32,
);
if !use_expr {
@ -228,7 +228,7 @@ impl ByteCompiler<'_, '_> {
match access.field() {
PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
}
PropertyAccessField::Expr(field) => {
self.compile_expr(field, true);
@ -240,7 +240,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(access.target(), true);
self.emit(Opcode::Dup, &[]);
let index = self.get_or_insert_private_name(access.field());
self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPrivateField, index);
}
expr => {
self.emit_opcode(Opcode::PushUndefined);
@ -267,8 +267,10 @@ impl ByteCompiler<'_, '_> {
));
}
self.emit(Opcode::TemplateCreate, &[Operand::U32(count)]);
self.emit_u64(site);
self.emit(
Opcode::TemplateCreate,
&[Operand::Varying(count), Operand::U64(site)],
);
self.patch_jump(jump_label);
@ -276,10 +278,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(expr, true);
}
self.emit(
Opcode::Call,
&[Operand::U32(template.exprs().len() as u32 + 1)],
);
self.emit_with_varying_operand(Opcode::Call, template.exprs().len() as u32 + 1);
}
Expression::Class(class) => self.class(class, true),
Expression::SuperCall(super_call) => {
@ -310,9 +309,9 @@ impl ByteCompiler<'_, '_> {
if contains_spread {
self.emit_opcode(Opcode::SuperCallSpread);
} else {
self.emit(
self.emit_with_varying_operand(
Opcode::SuperCall,
&[Operand::U32(super_call.arguments().len() as u32)],
super_call.arguments().len() as u32,
);
}

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

@ -18,7 +18,7 @@ impl ByteCompiler<'_, '_> {
PropertyDefinition::IdentifierReference(ident) => {
let index = self.get_or_insert_name(*ident);
self.access_get(Access::Variable { name: *ident }, true);
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
}
PropertyDefinition::Property(name, expr) => match name {
PropertyName::Literal(name) => {
@ -27,7 +27,7 @@ impl ByteCompiler<'_, '_> {
if *name == Sym::__PROTO__ && !self.json_parse {
self.emit_opcode(Opcode::SetPrototype);
} else {
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
}
}
PropertyName::Computed(name_node) => {
@ -49,7 +49,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertyGetterByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPropertyGetterByName, index);
}
PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method(
@ -64,7 +64,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertySetterByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPropertySetterByName, index);
}
PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method(
@ -79,7 +79,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
}
PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method(
@ -94,7 +94,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
}
PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method(
@ -109,7 +109,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
}
PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method(
@ -124,7 +124,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
}
PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method(
@ -140,7 +140,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Swap);
self.emit(
Opcode::CopyDataProperties,
&[Operand::U32(0), Operand::U32(0)],
&[Operand::Varying(0), Operand::Varying(0)],
);
self.emit_opcode(Opcode::Pop);
}

4
boa_engine/src/bytecompiler/expression/unary.rs

@ -4,7 +4,7 @@ use boa_ast::{
};
use crate::{
bytecompiler::{Access, ByteCompiler, Operand},
bytecompiler::{Access, ByteCompiler},
vm::Opcode,
};
@ -29,7 +29,7 @@ impl ByteCompiler<'_, '_> {
Expression::Identifier(identifier) => {
let binding = self.get_binding_value(*identifier);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::GetNameOrUndefined, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetNameOrUndefined, index);
}
expr => self.compile_expr(expr, true),
}

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

@ -28,9 +28,9 @@ impl ByteCompiler<'_, '_> {
let lex = self.current_environment.is_lex_binding(name);
if lex {
self.emit(Opcode::GetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetName, index);
} else {
self.emit(Opcode::GetNameAndLocator, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetNameAndLocator, index);
}
self.emit_opcode(opcode);
@ -44,11 +44,11 @@ impl ByteCompiler<'_, '_> {
match self.set_mutable_binding(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetName, index);
}
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index);
}
Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop);
@ -67,13 +67,13 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
self.emit_opcode(opcode);
if post {
self.emit(Opcode::RotateRight, &[Operand::U8(4)]);
}
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if post {
self.emit_opcode(Opcode::Pop);
}
@ -102,13 +102,13 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPrivateField, index);
self.emit_opcode(opcode);
if post {
self.emit(Opcode::RotateRight, &[Operand::U8(3)]);
}
self.emit(Opcode::SetPrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPrivateField, index);
if post {
self.emit_opcode(Opcode::Pop);
}
@ -122,13 +122,13 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::This);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
self.emit_opcode(opcode);
if post {
self.emit(Opcode::RotateRight, &[Operand::U8(3)]);
}
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if post {
self.emit_opcode(Opcode::Pop);
}

173
boa_engine/src/bytecompiler/mod.rs

@ -17,7 +17,10 @@ use crate::{
builtins::function::ThisMode,
environments::{BindingLocator, BindingLocatorError, CompileTimeEnvironment},
js_string,
vm::{BindingOpcode, CodeBlock, CodeBlockFlags, GeneratorResumeKind, Handler, Opcode},
vm::{
BindingOpcode, CodeBlock, CodeBlockFlags, GeneratorResumeKind, Handler, Opcode,
VaryingOperandKind,
},
Context, JsBigInt, JsString, JsValue,
};
use boa_ast::{
@ -223,6 +226,7 @@ pub(crate) enum Operand {
U32(u32),
I64(i64),
U64(u64),
Varying(u32),
}
/// The [`ByteCompiler`] is used to compile ECMAScript AST from [`boa_ast`] to bytecode.
@ -406,18 +410,18 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
BindingOpcode::Var => {
let binding = self.initialize_mutable_binding(name, true);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::DefVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefVar, index);
}
BindingOpcode::InitVar => {
if self.has_binding(name) {
match self.set_mutable_binding(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefInitVar, index);
}
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index);
}
Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop);
@ -426,27 +430,27 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
} else {
let binding = self.initialize_mutable_binding(name, true);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefInitVar, index);
};
}
BindingOpcode::InitLet => {
let binding = self.initialize_mutable_binding(name, false);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::PutLexicalValue, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::PutLexicalValue, index);
}
BindingOpcode::InitConst => {
let binding = self.initialize_immutable_binding(name);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::PutLexicalValue, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::PutLexicalValue, index);
}
BindingOpcode::SetName => match self.set_mutable_binding(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetName, index);
}
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index);
}
Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop);
@ -461,13 +465,49 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
}
pub(crate) fn emit(&mut self, opcode: Opcode, operands: &[Operand]) {
let mut varying_kind = VaryingOperandKind::U8;
for operand in operands {
if let Operand::Varying(operand) = *operand {
if u8::try_from(operand).is_ok() {
} else if u16::try_from(operand).is_ok() {
varying_kind = VaryingOperandKind::U16;
} else {
varying_kind = VaryingOperandKind::U32;
break;
}
}
}
match varying_kind {
VaryingOperandKind::U8 => {}
VaryingOperandKind::U16 => self.emit_opcode(Opcode::U16Operands),
VaryingOperandKind::U32 => self.emit_opcode(Opcode::U32Operands),
}
self.emit_opcode(opcode);
for operand in operands {
self.emit_operand(*operand);
self.emit_operand(*operand, varying_kind);
}
}
pub(crate) fn emit_operand(&mut self, operand: Operand) {
/// Emits an opcode with one varying operand.
///
/// Simpler version of [`ByteCompiler::emit()`].
pub(crate) fn emit_with_varying_operand(&mut self, opcode: Opcode, operand: u32) {
if let Ok(operand) = u8::try_from(operand) {
self.emit_opcode(opcode);
self.emit_u8(operand);
} else if let Ok(operand) = u16::try_from(operand) {
self.emit_opcode(Opcode::U16Operands);
self.emit_opcode(opcode);
self.emit_u16(operand);
} else {
self.emit_opcode(Opcode::U32Operands);
self.emit_opcode(opcode);
self.emit_u32(operand);
}
}
pub(crate) fn emit_operand(&mut self, operand: Operand, varying_kind: VaryingOperandKind) {
match operand {
Operand::Bool(v) => self.emit_u8(v.into()),
Operand::I8(v) => self.emit_i8(v),
@ -478,6 +518,11 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
Operand::U32(v) => self.emit_u32(v),
Operand::I64(v) => self.emit_i64(v),
Operand::U64(v) => self.emit_u64(v),
Operand::Varying(v) => match varying_kind {
VaryingOperandKind::U8 => self.emit_u8(v as u8),
VaryingOperandKind::U16 => self.emit_u16(v as u16),
VaryingOperandKind::U32 => self.emit_u32(v),
},
}
}
@ -533,7 +578,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
fn emit_push_literal(&mut self, literal: Literal) {
let index = self.get_or_insert_literal(literal);
self.emit(Opcode::PushLiteral, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::PushLiteral, index);
}
fn emit_push_rational(&mut self, value: f64) {
@ -655,7 +700,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
Access::Variable { name } => {
let binding = self.get_binding_value(name);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::GetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetName, index);
}
Access::Property { access } => match access {
PropertyAccess::Simple(access) => match access.field() {
@ -663,7 +708,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
let index = self.get_or_insert_name((*name).into());
self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
}
PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true);
@ -675,14 +720,14 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccess::Private(access) => {
let index = self.get_or_insert_private_name(access.field());
self.compile_expr(access.target(), true);
self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPrivateField, index);
}
PropertyAccess::Super(access) => match access.field() {
PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into());
self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::This);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
}
PropertyAccessField::Expr(expr) => {
self.emit_opcode(Opcode::Super);
@ -723,7 +768,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
let lex = self.current_environment.is_lex_binding(name);
if !lex {
self.emit(Opcode::GetLocator, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetLocator, index);
}
expr_fn(self, 0);
@ -735,11 +780,11 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
match self.set_mutable_binding(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetName, index);
}
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index);
}
Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop);
@ -757,7 +802,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
expr_fn(self, 2);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if !use_expr {
self.emit_opcode(Opcode::Pop);
}
@ -777,7 +822,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.compile_expr(access.target(), true);
expr_fn(self, 1);
let index = self.get_or_insert_private_name(access.field());
self.emit(Opcode::SetPrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPrivateField, index);
if !use_expr {
self.emit_opcode(Opcode::Pop);
}
@ -788,7 +833,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.emit_opcode(Opcode::This);
expr_fn(self, 1);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if !use_expr {
self.emit_opcode(Opcode::Pop);
}
@ -816,7 +861,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Const(name) => {
let index = self.get_or_insert_name((*name).into());
self.compile_expr(access.target(), true);
self.emit(Opcode::DeletePropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DeletePropertyByName, index);
}
PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true);
@ -833,7 +878,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
Access::Variable { name } => {
let binding = self.get_binding_value(name);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::DeleteName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DeleteName, index);
}
Access::This => {
self.emit_opcode(Opcode::PushTrue);
@ -895,7 +940,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
match access.field() {
PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
}
PropertyAccessField::Expr(field) => {
self.compile_expr(field, true);
@ -907,7 +952,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
let index = self.get_or_insert_private_name(access.field());
self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPrivateField, index);
}
PropertyAccess::Super(access) => {
self.emit_opcode(Opcode::This);
@ -916,7 +961,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
match access.field() {
PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
}
PropertyAccessField::Expr(expr) => {
self.compile_expr(expr, true);
@ -1002,7 +1047,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
match field {
PropertyAccessField::Const(name) => {
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
}
PropertyAccessField::Expr(expr) => {
self.compile_expr(expr, true);
@ -1015,7 +1060,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
OptionalOperationKind::PrivatePropertyAccess { field } => {
self.emit_opcode(Opcode::Dup);
let index = self.get_or_insert_private_name(*field);
self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetPrivateField, index);
self.emit(Opcode::RotateLeft, &[Operand::U8(3)]);
self.emit_opcode(Opcode::Pop);
}
@ -1039,7 +1084,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
for arg in args {
self.compile_expr(arg, true);
}
self.emit(Opcode::Call, &[Operand::U32(args.len() as u32)]);
self.emit_with_varying_operand(Opcode::Call, args.len() as u32);
}
self.emit_opcode(Opcode::PushUndefined);
@ -1148,16 +1193,16 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
if self.annex_b_function_names.contains(&name) {
let binding = self.get_binding_value(name);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::GetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetName, index);
match self.set_mutable_binding_var(name) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::SetName, index);
}
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name);
self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index);
}
Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop);
@ -1235,28 +1280,22 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
let index = self.function(function);
if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator {
self.emit(Opcode::GetGenerator, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async && arrow {
self.emit(
Opcode::GetAsyncArrowFunction,
&[Operand::U32(index), Operand::Bool(false)],
);
self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]);
} else if r#async {
self.emit(
Opcode::GetFunctionAsync,
&[Operand::U32(index), Operand::Bool(false)],
&[Operand::Varying(index), Operand::Bool(false)],
);
} else if arrow {
self.emit(
Opcode::GetArrowFunction,
&[Operand::U32(index), Operand::Bool(false)],
);
self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]);
} else {
self.emit(
Opcode::GetFunction,
&[Operand::U32(index), Operand::Bool(false)],
&[Operand::Varying(index), Operand::Bool(false)],
);
}
@ -1318,28 +1357,22 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.functions.push(code);
if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator {
self.emit(Opcode::GetGenerator, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async && arrow {
self.emit(
Opcode::GetAsyncArrowFunction,
&[Operand::U32(index), Operand::Bool(true)],
);
self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]);
} else if r#async {
self.emit(
Opcode::GetFunctionAsync,
&[Operand::U32(index), Operand::Bool(true)],
&[Operand::Varying(index), Operand::Bool(true)],
);
} else if arrow {
self.emit(
Opcode::GetArrowFunction,
&[Operand::U32(index), Operand::Bool(true)],
);
self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]);
} else {
self.emit(
Opcode::GetFunction,
&[Operand::U32(index), Operand::Bool(true)],
&[Operand::Varying(index), Operand::Bool(true)],
);
}
}
@ -1388,28 +1421,22 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.functions.push(code);
if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator {
self.emit(Opcode::GetGenerator, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async && arrow {
self.emit(
Opcode::GetAsyncArrowFunction,
&[Operand::U32(index), Operand::Bool(true)],
);
self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]);
} else if r#async {
self.emit(
Opcode::GetFunctionAsync,
&[Operand::U32(index), Operand::Bool(true)],
&[Operand::Varying(index), Operand::Bool(true)],
);
} else if arrow {
self.emit(
Opcode::GetArrowFunction,
&[Operand::U32(index), Operand::Bool(true)],
);
self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]);
} else {
self.emit(
Opcode::GetFunction,
&[Operand::U32(index), Operand::Bool(true)],
&[Operand::Varying(index), Operand::Bool(true)],
);
}
}
@ -1474,12 +1501,14 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
match kind {
CallKind::CallEval if contains_spread => self.emit_opcode(Opcode::CallEvalSpread),
CallKind::CallEval => {
self.emit(Opcode::CallEval, &[Operand::U32(call.args().len() as u32)]);
self.emit_with_varying_operand(Opcode::CallEval, call.args().len() as u32);
}
CallKind::Call if contains_spread => self.emit_opcode(Opcode::CallSpread),
CallKind::Call => self.emit(Opcode::Call, &[Operand::U32(call.args().len() as u32)]),
CallKind::Call => {
self.emit_with_varying_operand(Opcode::Call, call.args().len() as u32);
}
CallKind::New if contains_spread => self.emit_opcode(Opcode::NewSpread),
CallKind::New => self.emit(Opcode::New, &[Operand::U32(call.args().len() as u32)]),
CallKind::New => self.emit_with_varying_operand(Opcode::New, call.args().len() as u32),
}
if !use_expr {

8
boa_engine/src/bytecompiler/statement/loop.rs

@ -69,13 +69,13 @@ impl ByteCompiler<'_, '_> {
if let Some(let_binding_indices) = let_binding_indices {
for index in &let_binding_indices {
self.emit(Opcode::GetName, &[Operand::U32(*index)]);
self.emit_with_varying_operand(Opcode::GetName, *index);
}
self.emit_opcode(Opcode::PopEnvironment);
iteration_env_labels =
Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment));
for index in let_binding_indices.iter().rev() {
self.emit(Opcode::PutLexicalValue, &[Operand::U32(*index)]);
self.emit_with_varying_operand(Opcode::PutLexicalValue, *index);
}
}
@ -303,11 +303,11 @@ impl ByteCompiler<'_, '_> {
match self.set_mutable_binding(*ident) {
Ok(binding) => {
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::DefInitVar, index);
}
Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(*ident);
self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]);
self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index);
}
Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop);

2
boa_engine/src/bytecompiler/utils.rs

@ -36,7 +36,7 @@ impl ByteCompiler<'_, '_> {
let error_msg = self.get_or_insert_literal(Literal::String(js_string!(
"inner result was not an object"
)));
self.emit(Opcode::ThrowNewTypeError, &[Operand::U32(error_msg)]);
self.emit_with_varying_operand(Opcode::ThrowNewTypeError, error_msg);
self.patch_jump(skip_return);
self.emit_opcode(Opcode::IteratorPop);

4
boa_engine/src/module/source.rs

@ -22,7 +22,7 @@ use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
use crate::{
builtins::{promise::PromiseCapability, Promise},
bytecompiler::{ByteCompiler, FunctionSpec, Operand},
bytecompiler::{ByteCompiler, FunctionSpec},
environments::{BindingLocator, CompileTimeEnvironment, EnvironmentStack},
module::ModuleKind,
object::{FunctionObjectBuilder, JsPromise, RecursionLimiter},
@ -1501,7 +1501,7 @@ impl SourceTextModule {
let binding = compiler.initialize_mutable_binding(name, false);
let index = compiler.get_or_insert_binding(binding);
compiler.emit_opcode(Opcode::PushUndefined);
compiler.emit(Opcode::DefInitVar, &[Operand::U32(index)]);
compiler.emit_with_varying_operand(Opcode::DefInitVar, index);
// 3. Append dn to declaredVarNames.
declared_var_names.push(name);
}

109
boa_engine/src/vm/code_block.rs

@ -21,7 +21,8 @@ use std::{cell::Cell, mem::size_of, rc::Rc};
use thin_vec::ThinVec;
#[cfg(any(feature = "trace", feature = "flowgraph"))]
use crate::vm::Opcode;
use super::{Instruction, InstructionIterator};
#[cfg(any(feature = "trace", feature = "flowgraph"))]
use boa_interner::{Interner, ToInternedString};
@ -299,10 +300,11 @@ impl CodeBlock {
///
/// Returns an empty `String` if no operands are present.
#[cfg(any(feature = "trace", feature = "flowgraph"))]
pub(crate) fn instruction_operands(&self, pc: &mut usize, interner: &Interner) -> String {
use super::Instruction;
let instruction = Instruction::from_bytecode(&self.bytecode, pc);
pub(crate) fn instruction_operands(
&self,
instruction: &Instruction,
interner: &Interner,
) -> String {
match instruction {
Instruction::SetFunctionName { prefix } => match prefix {
0 => "prefix: none",
@ -318,11 +320,11 @@ impl CodeBlock {
Instruction::PushInt8 { value } => value.to_string(),
Instruction::PushInt16 { value } => value.to_string(),
Instruction::PushInt32 { value } => value.to_string(),
Instruction::PushFloat { value } => ryu_js::Buffer::new().format(value).to_string(),
Instruction::PushDouble { value } => ryu_js::Buffer::new().format(value).to_string(),
Instruction::PushLiteral { index: value }
| Instruction::ThrowNewTypeError { message: value }
| Instruction::Jump { address: value }
Instruction::PushFloat { value } => ryu_js::Buffer::new().format(*value).to_string(),
Instruction::PushDouble { value } => ryu_js::Buffer::new().format(*value).to_string(),
Instruction::PushLiteral { index }
| Instruction::ThrowNewTypeError { message: index } => index.value().to_string(),
Instruction::Jump { address: value }
| Instruction::JumpIfTrue { address: value }
| Instruction::JumpIfFalse { address: value }
| Instruction::JumpIfNotUndefined { address: value }
@ -331,8 +333,8 @@ impl CodeBlock {
| Instruction::Default { address: value }
| Instruction::LogicalAnd { exit: value }
| Instruction::LogicalOr { exit: value }
| Instruction::Coalesce { exit: value }
| Instruction::CallEval {
| Instruction::Coalesce { exit: value } => value.to_string(),
Instruction::CallEval {
argument_count: value,
}
| Instruction::Call {
@ -344,7 +346,7 @@ impl CodeBlock {
| Instruction::SuperCall {
argument_count: value,
}
| Instruction::ConcatToString { value_count: value } => value.to_string(),
| Instruction::ConcatToString { value_count: value } => value.value().to_string(),
Instruction::PushDeclarativeEnvironment {
compile_environments_index,
}
@ -354,8 +356,8 @@ impl CodeBlock {
Instruction::CopyDataProperties {
excluded_key_count: value1,
excluded_key_count_computed: value2,
}
| Instruction::GeneratorDelegateNext {
} => format!("{}, {}", value1.value(), value2.value()),
Instruction::GeneratorDelegateNext {
return_method_undefined: value1,
throw_method_undefined: value2,
}
@ -365,29 +367,28 @@ impl CodeBlock {
} => {
format!("{value1}, {value2}")
}
Instruction::TemplateLookup { exit: value, site }
| Instruction::TemplateCreate { count: value, site } => {
format!("{value}, {site}")
Instruction::TemplateLookup { exit: value, site } => format!("{value}, {site}"),
Instruction::TemplateCreate { count, site } => {
format!("{}, {site}", count.value())
}
Instruction::GetArrowFunction { index, method }
| Instruction::GetAsyncArrowFunction { index, method }
| Instruction::GetFunction { index, method }
Instruction::GetFunction { index, method }
| Instruction::GetFunctionAsync { index, method } => {
let index = index.value() as usize;
format!(
"{index:04}: '{}' (length: {}), method: {method}",
self.functions[index as usize]
.name()
.to_std_string_escaped(),
self.functions[index as usize].length
self.functions[index].name().to_std_string_escaped(),
self.functions[index].length
)
}
Instruction::GetGenerator { index } | Instruction::GetGeneratorAsync { index } => {
Instruction::GetArrowFunction { index }
| Instruction::GetAsyncArrowFunction { index }
| Instruction::GetGenerator { index }
| Instruction::GetGeneratorAsync { index } => {
let index = index.value() as usize;
format!(
"{index:04}: '{}' (length: {})",
self.functions[index as usize]
.name()
.to_std_string_escaped(),
self.functions[index as usize].length
self.functions[index].name().to_std_string_escaped(),
self.functions[index].length
)
}
Instruction::DefVar { index }
@ -400,12 +401,12 @@ impl CodeBlock {
| Instruction::SetName { index }
| Instruction::DeleteName { index } => {
format!(
"{index:04}: '{}'",
interner.resolve_expect(self.bindings[index as usize].name().sym()),
"{:04}: '{}'",
index.value(),
interner.resolve_expect(self.bindings[index.value() as usize].name().sym()),
)
}
Instruction::GetPropertyByName { index }
| Instruction::GetMethod { index }
| Instruction::SetPropertyByName { index }
| Instruction::DefineOwnPropertyByName { index }
| Instruction::DefineClassStaticMethodByName { index }
@ -416,6 +417,8 @@ impl CodeBlock {
| Instruction::SetPropertySetterByName { index }
| Instruction::DefineClassStaticSetterByName { index }
| Instruction::DefineClassSetterByName { index }
| Instruction::InPrivate { index }
| Instruction::ThrowMutateImmutable { index }
| Instruction::DeletePropertyByName { index }
| Instruction::SetPrivateField { index }
| Instruction::DefinePrivateField { index }
@ -426,12 +429,11 @@ impl CodeBlock {
| Instruction::PushClassFieldPrivate { index }
| Instruction::PushClassPrivateGetter { index }
| Instruction::PushClassPrivateSetter { index }
| Instruction::PushClassPrivateMethod { index }
| Instruction::InPrivate { index }
| Instruction::ThrowMutateImmutable { index } => {
| Instruction::PushClassPrivateMethod { index } => {
format!(
"{index:04}: '{}'",
self.names[index as usize].to_std_string_escaped(),
"{:04}: '{}'",
index.value(),
self.names[index.value() as usize].to_std_string_escaped(),
)
}
Instruction::PushPrivateEnvironment { name_indices } => {
@ -571,7 +573,10 @@ impl CodeBlock {
| Instruction::GetReturnValue
| Instruction::SetReturnValue
| Instruction::Nop => String::new(),
Instruction::Reserved1
Instruction::U16Operands
| Instruction::U32Operands
| Instruction::Reserved1
| Instruction::Reserved2
| Instruction::Reserved3
| Instruction::Reserved4
@ -627,8 +632,7 @@ impl CodeBlock {
| Instruction::Reserved54
| Instruction::Reserved55
| Instruction::Reserved56
| Instruction::Reserved57
| Instruction::Reserved58 => unreachable!("Reserved opcodes are unrechable"),
| Instruction::Reserved57 => unreachable!("Reserved opcodes are unrechable"),
}
}
}
@ -648,15 +652,14 @@ impl ToInternedString for CodeBlock {
format!("Compiled Output: '{}'", name.to_std_string_escaped()),
));
let mut pc = 0;
let mut count = 0;
while pc < self.bytecode.len() {
let instruction_start_pc = pc;
let mut iterator = InstructionIterator::new(&self.bytecode);
let opcode: Opcode = self.bytecode[instruction_start_pc].into();
let opcode = opcode.as_str();
let previous_pc = pc;
let operands = self.instruction_operands(&mut pc, interner);
let mut count = 0;
while let Some((instruction_start_pc, varying_operand_kind, instruction)) = iterator.next()
{
let opcode = instruction.opcode().as_str();
let operands = self.instruction_operands(&instruction, interner);
let pc = iterator.pc();
let handler = if let Some((i, handler)) = self.find_handler(instruction_start_pc as u32)
{
@ -672,8 +675,14 @@ impl ToInternedString for CodeBlock {
" none ".to_string()
};
let varying_operand_kind = match varying_operand_kind {
super::VaryingOperandKind::U8 => "",
super::VaryingOperandKind::U16 => ".U16",
super::VaryingOperandKind::U32 => ".U32",
};
f.push_str(&format!(
"{previous_pc:06} {count:04} {handler} {opcode:<27}{operands}\n",
"{instruction_start_pc:06} {count:04} {handler} {opcode}{varying_operand_kind:<27}{operands}\n",
));
count += 1;
}

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

@ -14,7 +14,7 @@ pub use edge::*;
pub use graph::*;
pub use node::*;
use super::Instruction;
use super::{Instruction, InstructionIterator};
impl CodeBlock {
/// Output the [`CodeBlock`] VM instructions into a [`Graph`].
@ -29,19 +29,18 @@ impl CodeBlock {
graph.set_label(name);
let mut pc = 0;
while pc < self.bytecode.len() {
let previous_pc = pc;
let instruction = Instruction::from_bytecode(&self.bytecode, &mut pc);
let mut iterator = InstructionIterator::new(&self.bytecode);
while let Some((previous_pc, _, instruction)) = iterator.next() {
let opcode = instruction.opcode();
let opcode_str = opcode.as_str();
let mut tmp = previous_pc;
let label = format!(
"{opcode_str} {}",
self.instruction_operands(&mut tmp, interner)
self.instruction_operands(&instruction, interner)
);
let pc = iterator.pc();
match instruction {
Instruction::SetFunctionName { .. } => {
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None);
@ -77,11 +76,7 @@ impl CodeBlock {
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None);
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
}
Instruction::PushLiteral { index } => {
let operand_str = self.literals[index as usize].display().to_string();
let operand_str = operand_str.escape_debug();
let label = format!("{opcode_str} {operand_str}");
Instruction::PushLiteral { .. } => {
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None);
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
}
@ -271,7 +266,6 @@ impl CodeBlock {
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
}
Instruction::GetPropertyByName { .. }
| Instruction::GetMethod { .. }
| Instruction::SetPropertyByName { .. }
| Instruction::DefineOwnPropertyByName { .. }
| Instruction::DefineClassStaticMethodByName { .. }
@ -471,7 +465,9 @@ impl CodeBlock {
Instruction::Return => {
graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::Red);
}
Instruction::Reserved1
Instruction::U16Operands
| Instruction::U32Operands
| Instruction::Reserved1
| Instruction::Reserved2
| Instruction::Reserved3
| Instruction::Reserved4
@ -527,8 +523,7 @@ impl CodeBlock {
| Instruction::Reserved54
| Instruction::Reserved55
| Instruction::Reserved56
| Instruction::Reserved57
| Instruction::Reserved58 => unreachable!("Reserved opcodes are unrechable"),
| Instruction::Reserved57 => unreachable!("Reserved opcodes are unrechable"),
}
}

22
boa_engine/src/vm/mod.rs

@ -32,11 +32,11 @@ mod runtime_limits;
#[cfg(feature = "flowgraph")]
pub mod flowgraph;
pub(crate) use opcode::{Instruction, InstructionIterator, Opcode, VaryingOperandKind};
pub use runtime_limits::RuntimeLimits;
pub use {
call_frame::{CallFrame, GeneratorResumeKind},
code_block::CodeBlock,
opcode::{Instruction, InstructionIterator, Opcode},
};
pub(crate) use {
@ -246,13 +246,16 @@ impl Context<'_> {
}
fn trace_execute_instruction(&mut self) -> JsResult<CompletionType> {
let mut pc = self.vm.frame().pc as usize;
let opcode: Opcode = self.vm.frame().code_block.read::<u8>(pc).into();
let bytecodes = &self.vm.frame().code_block.bytecode;
let pc = self.vm.frame().pc as usize;
let (_, varying_operand_kind, instruction) = InstructionIterator::with_pc(bytecodes, pc)
.next()
.expect("There should be an instruction left");
let operands = self
.vm
.frame()
.code_block
.instruction_operands(&mut pc, self.interner());
.instruction_operands(&instruction, self.interner());
let instant = Instant::now();
let result = self.execute_instruction();
@ -279,10 +282,17 @@ impl Context<'_> {
stack
};
let varying_operand_kind = match varying_operand_kind {
VaryingOperandKind::U8 => "",
VaryingOperandKind::U16 => ".U16",
VaryingOperandKind::U32 => ".U32",
};
println!(
"{:<TIME_COLUMN_WIDTH$} {:<OPCODE_COLUMN_WIDTH$} {operands:<OPERAND_COLUMN_WIDTH$} {stack}",
"{:<TIME_COLUMN_WIDTH$} {}{:<OPCODE_COLUMN_WIDTH$} {operands:<OPERAND_COLUMN_WIDTH$} {stack}",
format!("{}μs", duration.as_micros()),
opcode.as_str(),
instruction.opcode().as_str(),
varying_operand_kind,
TIME_COLUMN_WIDTH = Self::TIME_COLUMN_WIDTH,
OPCODE_COLUMN_WIDTH = Self::OPCODE_COLUMN_WIDTH,
OPERAND_COLUMN_WIDTH = Self::OPERAND_COLUMN_WIDTH,

30
boa_engine/src/vm/opcode/binary_ops/mod.rs

@ -105,13 +105,9 @@ impl Operation for In {
#[derive(Debug, Clone, Copy)]
pub(crate) struct InPrivate;
impl Operation for InPrivate {
const NAME: &'static str = "InPrivate";
const INSTRUCTION: &'static str = "INST - InPrivate";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl InPrivate {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let rhs = context.vm.pop();
let Some(rhs) = rhs.as_object() else {
@ -138,6 +134,26 @@ impl Operation for InPrivate {
}
}
impl Operation for InPrivate {
const NAME: &'static str = "InPrivate";
const INSTRUCTION: &'static str = "INST - InPrivate";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `InstanceOf` implements the Opcode Operation for `Opcode::InstanceOf`
///
/// Operation:

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

@ -14,11 +14,8 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct CallEval;
impl Operation for CallEval {
const NAME: &'static str = "CallEval";
const INSTRUCTION: &'static str = "INST - CallEval";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
impl CallEval {
fn operation(context: &mut Context<'_>, argument_count: usize) -> JsResult<CompletionType> {
if context.vm.runtime_limits.recursion_limit() <= context.vm.frames.len() {
return Err(JsNativeError::runtime_limit()
.with_message(format!(
@ -32,8 +29,7 @@ impl Operation for CallEval {
.with_message("Maximum call stack size exceeded")
.into());
}
let argument_count = context.vm.read::<u32>();
let mut arguments = Vec::with_capacity(argument_count as usize);
let mut arguments = Vec::with_capacity(argument_count);
for _ in 0..argument_count {
arguments.push(context.vm.pop());
}
@ -75,6 +71,26 @@ impl Operation for CallEval {
}
}
impl Operation for CallEval {
const NAME: &'static str = "CallEval";
const INSTRUCTION: &'static str = "INST - CallEval";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u8>();
Self::operation(context, argument_count as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u16>() as usize;
Self::operation(context, argument_count)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u32>();
Self::operation(context, argument_count as usize)
}
}
/// `CallEvalSpread` implements the Opcode Operation for `Opcode::CallEvalSpread`
///
/// Operation:
@ -156,11 +172,8 @@ impl Operation for CallEvalSpread {
#[derive(Debug, Clone, Copy)]
pub(crate) struct Call;
impl Operation for Call {
const NAME: &'static str = "Call";
const INSTRUCTION: &'static str = "INST - Call";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
impl Call {
fn operation(context: &mut Context<'_>, argument_count: usize) -> JsResult<CompletionType> {
if context.vm.runtime_limits.recursion_limit() <= context.vm.frames.len() {
return Err(JsNativeError::runtime_limit()
.with_message(format!(
@ -174,8 +187,7 @@ impl Operation for Call {
.with_message("Maximum call stack size exceeded")
.into());
}
let argument_count = context.vm.read::<u32>();
let mut arguments = Vec::with_capacity(argument_count as usize);
let mut arguments = Vec::with_capacity(argument_count);
for _ in 0..argument_count {
arguments.push(context.vm.pop());
}
@ -200,6 +212,26 @@ impl Operation for Call {
}
}
impl Operation for Call {
const NAME: &'static str = "Call";
const INSTRUCTION: &'static str = "INST - Call";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u8>();
Self::operation(context, argument_count as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u16>() as usize;
Self::operation(context, argument_count)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u32>();
Self::operation(context, argument_count as usize)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct CallSpread;

30
boa_engine/src/vm/opcode/concat/mod.rs

@ -10,13 +10,9 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct ConcatToString;
impl Operation for ConcatToString {
const NAME: &'static str = "ConcatToString";
const INSTRUCTION: &'static str = "INST - ConcatToString";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u32>();
let mut strings = Vec::with_capacity(value_count as usize);
impl ConcatToString {
fn operation(context: &mut Context<'_>, value_count: usize) -> JsResult<CompletionType> {
let mut strings = Vec::with_capacity(value_count);
for _ in 0..value_count {
strings.push(context.vm.pop().to_string(context)?);
}
@ -31,3 +27,23 @@ impl Operation for ConcatToString {
Ok(CompletionType::Normal)
}
}
impl Operation for ConcatToString {
const NAME: &'static str = "ConcatToString";
const INSTRUCTION: &'static str = "INST - ConcatToString";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u8>() as usize;
Self::operation(context, value_count)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u16>() as usize;
Self::operation(context, value_count)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u32>() as usize;
Self::operation(context, value_count)
}
}

30
boa_engine/src/vm/opcode/control_flow/throw.rs

@ -117,13 +117,9 @@ impl Operation for MaybeException {
#[derive(Debug, Clone, Copy)]
pub(crate) struct ThrowNewTypeError;
impl Operation for ThrowNewTypeError {
const NAME: &'static str = "ThrowNewTypeError";
const INSTRUCTION: &'static str = "INST - ThrowNewTypeError";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let msg = context.vm.frame().code_block.literals[index as usize]
impl ThrowNewTypeError {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let msg = context.vm.frame().code_block.literals[index]
.as_string()
.expect("throw message must be a string")
.clone();
@ -133,3 +129,23 @@ impl Operation for ThrowNewTypeError {
Err(JsNativeError::typ().with_message(msg).into())
}
}
impl Operation for ThrowNewTypeError {
const NAME: &'static str = "ThrowNewTypeError";
const INSTRUCTION: &'static str = "INST - ThrowNewTypeError";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}

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

@ -10,14 +10,13 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct CopyDataProperties;
impl Operation for CopyDataProperties {
const NAME: &'static str = "CopyDataProperties";
const INSTRUCTION: &'static str = "INST - CopyDataProperties";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let excluded_key_count = context.vm.read::<u32>();
let excluded_key_count_computed = context.vm.read::<u32>();
let mut excluded_keys = Vec::with_capacity(excluded_key_count as usize);
impl CopyDataProperties {
fn operation(
context: &mut Context<'_>,
excluded_key_count: usize,
excluded_key_count_computed: usize,
) -> JsResult<CompletionType> {
let mut excluded_keys = Vec::with_capacity(excluded_key_count);
for _ in 0..excluded_key_count {
let key = context.vm.pop();
excluded_keys.push(
@ -40,3 +39,26 @@ impl Operation for CopyDataProperties {
Ok(CompletionType::Normal)
}
}
impl Operation for CopyDataProperties {
const NAME: &'static str = "CopyDataProperties";
const INSTRUCTION: &'static str = "INST - CopyDataProperties";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let excluded_key_count = context.vm.read::<u8>() as usize;
let excluded_key_count_computed = context.vm.read::<u8>() as usize;
Self::operation(context, excluded_key_count, excluded_key_count_computed)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let excluded_key_count = context.vm.read::<u16>() as usize;
let excluded_key_count_computed = context.vm.read::<u16>() as usize;
Self::operation(context, excluded_key_count, excluded_key_count_computed)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let excluded_key_count = context.vm.read::<u32>() as usize;
let excluded_key_count_computed = context.vm.read::<u32>() as usize;
Self::operation(context, excluded_key_count, excluded_key_count_computed)
}
}

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

@ -13,18 +13,12 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefineClassStaticGetterByName;
impl Operation for DefineClassStaticGetterByName {
const NAME: &'static str = "DefineClassStaticGetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassStaticGetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl DefineClassStaticGetterByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let function = context.vm.pop();
let class = context.vm.pop();
let class = class.as_object().expect("class must be object");
let key = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let key = context.vm.frame().code_block.names[index].clone().into();
{
let function_object = function
.as_object()
@ -56,6 +50,26 @@ impl Operation for DefineClassStaticGetterByName {
}
}
impl Operation for DefineClassStaticGetterByName {
const NAME: &'static str = "DefineClassStaticGetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassStaticGetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `DefineClassGetterByName` implements the Opcode Operation for `Opcode::DefineClassGetterByName`
///
/// Operation:
@ -63,18 +77,12 @@ impl Operation for DefineClassStaticGetterByName {
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefineClassGetterByName;
impl Operation for DefineClassGetterByName {
const NAME: &'static str = "DefineClassGetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassGetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl DefineClassGetterByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let function = context.vm.pop();
let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object");
let key = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let key = context.vm.frame().code_block.names[index].clone().into();
{
let function_object = function
.as_object()
@ -112,6 +120,26 @@ impl Operation for DefineClassGetterByName {
}
}
impl Operation for DefineClassGetterByName {
const NAME: &'static str = "DefineClassGetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassGetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `DefineClassStaticGetterByValue` implements the Opcode Operation for `Opcode::DefineClassStaticGetterByValue`
///
/// Operation:

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

@ -13,18 +13,12 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefineClassStaticMethodByName;
impl Operation for DefineClassStaticMethodByName {
const NAME: &'static str = "DefineClassStaticMethodByName";
const INSTRUCTION: &'static str = "INST - DefineClassStaticMethodByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl DefineClassStaticMethodByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let function = context.vm.pop();
let class = context.vm.pop();
let class = class.as_object().expect("class must be object");
let key = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let key = context.vm.frame().code_block.names[index].clone().into();
{
let function_object = function
.as_object()
@ -52,6 +46,26 @@ impl Operation for DefineClassStaticMethodByName {
}
}
impl Operation for DefineClassStaticMethodByName {
const NAME: &'static str = "DefineClassStaticMethodByName";
const INSTRUCTION: &'static str = "INST - DefineClassStaticMethodByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `DefineClassMethodByName` implements the Opcode Operation for `Opcode::DefineClassMethodByName`
///
/// Operation:
@ -59,18 +73,12 @@ impl Operation for DefineClassStaticMethodByName {
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefineClassMethodByName;
impl Operation for DefineClassMethodByName {
const NAME: &'static str = "DefineClassMethodByName";
const INSTRUCTION: &'static str = "INST - DefineClassMethodByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl DefineClassMethodByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let function = context.vm.pop();
let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object");
let key = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let key = context.vm.frame().code_block.names[index].clone().into();
{
let function_object = function
.as_object()
@ -104,6 +112,26 @@ impl Operation for DefineClassMethodByName {
}
}
impl Operation for DefineClassMethodByName {
const NAME: &'static str = "DefineClassMethodByName";
const INSTRUCTION: &'static str = "INST - DefineClassMethodByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `DefineClassStaticMethodByValue` implements the Opcode Operation for `Opcode::DefineClassStaticMethodByValue`
///
/// Operation:

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

@ -13,18 +13,12 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefineClassStaticSetterByName;
impl Operation for DefineClassStaticSetterByName {
const NAME: &'static str = "DefineClassStaticSetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassStaticSetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl DefineClassStaticSetterByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let function = context.vm.pop();
let class = context.vm.pop();
let class = class.as_object().expect("class must be object");
let key = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let key = context.vm.frame().code_block.names[index].clone().into();
{
let function_object = function
.as_object()
@ -57,6 +51,26 @@ impl Operation for DefineClassStaticSetterByName {
}
}
impl Operation for DefineClassStaticSetterByName {
const NAME: &'static str = "DefineClassStaticSetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassStaticSetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `DefineClassSetterByName` implements the Opcode Operation for `Opcode::DefineClassSetterByName`
///
/// Operation:
@ -64,18 +78,12 @@ impl Operation for DefineClassStaticSetterByName {
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefineClassSetterByName;
impl Operation for DefineClassSetterByName {
const NAME: &'static str = "DefineClassSetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassSetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl DefineClassSetterByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let function = context.vm.pop();
let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object");
let key = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let key = context.vm.frame().code_block.names[index].clone().into();
{
let function_object = function
.as_object()
@ -115,6 +123,26 @@ impl Operation for DefineClassSetterByName {
}
}
impl Operation for DefineClassSetterByName {
const NAME: &'static str = "DefineClassSetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassSetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `DefineClassStaticSetterByValue` implements the Opcode Operation for `Opcode::DefineClassStaticSetterByValue`
///
/// Operation:

95
boa_engine/src/vm/opcode/define/mod.rs

@ -16,14 +16,11 @@ pub(crate) use own_property::*;
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefVar;
impl Operation for DefVar {
const NAME: &'static str = "DefVar";
const INSTRUCTION: &'static str = "INST - DefVar";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
impl DefVar {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
// TODO: spec specifies to return `empty` on empty vars, but we're trying to initialize.
let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
let binding_locator = context.vm.frame().code_block.bindings[index];
if binding_locator.is_global() {
// already initialized at compile time
@ -31,13 +28,33 @@ impl Operation for DefVar {
context.vm.environments.put_value_if_uninitialized(
binding_locator.environment_index(),
binding_locator.binding_index(),
JsValue::Undefined,
JsValue::undefined(),
);
}
Ok(CompletionType::Normal)
}
}
impl Operation for DefVar {
const NAME: &'static str = "DefVar";
const INSTRUCTION: &'static str = "INST - DefVar";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
/// `DefInitVar` implements the Opcode Operation for `Opcode::DefInitVar`
///
/// Operation:
@ -45,14 +62,10 @@ impl Operation for DefVar {
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefInitVar;
impl Operation for DefInitVar {
const NAME: &'static str = "DefInitVar";
const INSTRUCTION: &'static str = "INST - DefInitVar";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl DefInitVar {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let value = context.vm.pop();
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
let mut binding_locator = context.vm.frame().code_block.bindings[index];
context.find_runtime_binding(&mut binding_locator)?;
@ -66,6 +79,26 @@ impl Operation for DefInitVar {
}
}
impl Operation for DefInitVar {
const NAME: &'static str = "DefInitVar";
const INSTRUCTION: &'static str = "INST - DefInitVar";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
/// `PutLexicalValue` implements the Opcode Operation for `Opcode::PutLexicalValue`
///
/// Operation:
@ -73,19 +106,37 @@ impl Operation for DefInitVar {
#[derive(Debug, Clone, Copy)]
pub(crate) struct PutLexicalValue;
impl Operation for PutLexicalValue {
const NAME: &'static str = "PutLexicalValue";
const INSTRUCTION: &'static str = "INST - PutLexicalValue";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl PutLexicalValue {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let value = context.vm.pop();
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
let binding_locator = context.vm.frame().code_block.bindings[index];
context.vm.environments.put_lexical_value(
binding_locator.environment_index(),
binding_locator.binding_index(),
value,
);
Ok(CompletionType::Normal)
}
}
impl Operation for PutLexicalValue {
const NAME: &'static str = "PutLexicalValue";
const INSTRUCTION: &'static str = "INST - PutLexicalValue";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}

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

@ -11,12 +11,8 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefineOwnPropertyByName;
impl Operation for DefineOwnPropertyByName {
const NAME: &'static str = "DefineOwnPropertyByName";
const INSTRUCTION: &'static str = "INST - DefineOwnPropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl DefineOwnPropertyByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let value = context.vm.pop();
let object = context.vm.pop();
let object = if let Some(object) = object.as_object() {
@ -24,7 +20,7 @@ impl Operation for DefineOwnPropertyByName {
} else {
object.to_object(context)?
};
let name = context.vm.frame().code_block.names[index as usize].clone();
let name = context.vm.frame().code_block.names[index].clone();
object.__define_own_property__(
&name.into(),
PropertyDescriptor::builder()
@ -39,6 +35,26 @@ impl Operation for DefineOwnPropertyByName {
}
}
impl Operation for DefineOwnPropertyByName {
const NAME: &'static str = "DefineOwnPropertyByName";
const INSTRUCTION: &'static str = "INST - DefineOwnPropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `DefineOwnPropertyByValue` implements the Opcode Operation for `Opcode::DefineOwnPropertyByValue`
///
/// Operation:

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

@ -11,17 +11,11 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct DeletePropertyByName;
impl Operation for DeletePropertyByName {
const NAME: &'static str = "DeletePropertyByName";
const INSTRUCTION: &'static str = "INST - DeletePropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl DeletePropertyByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let value = context.vm.pop();
let object = value.to_object(context)?;
let key = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let key = context.vm.frame().code_block.names[index].clone().into();
let result = object.__delete__(&key, context)?;
if !result && context.vm.frame().code_block.strict() {
return Err(JsNativeError::typ()
@ -33,6 +27,26 @@ impl Operation for DeletePropertyByName {
}
}
impl Operation for DeletePropertyByName {
const NAME: &'static str = "DeletePropertyByName";
const INSTRUCTION: &'static str = "INST - DeletePropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `DeletePropertyByValue` implements the Opcode Operation for `Opcode::DeletePropertyByValue`
///
/// Operation:
@ -67,13 +81,9 @@ impl Operation for DeletePropertyByValue {
#[derive(Debug, Clone, Copy)]
pub(crate) struct DeleteName;
impl Operation for DeleteName {
const NAME: &'static str = "DeleteName";
const INSTRUCTION: &'static str = "INST - DeleteName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
impl DeleteName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let mut binding_locator = context.vm.frame().code_block.bindings[index];
context.find_runtime_binding(&mut binding_locator)?;
@ -84,6 +94,26 @@ impl Operation for DeleteName {
}
}
impl Operation for DeleteName {
const NAME: &'static str = "DeleteName";
const INSTRUCTION: &'static str = "INST - DeleteName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
/// `DeleteSuperThrow` implements the Opcode Operation for `Opcode::DeleteSuperThrow`
///
/// Operation:

30
boa_engine/src/vm/opcode/environment/mod.rs

@ -108,13 +108,9 @@ impl Operation for SuperCallPrepare {
#[derive(Debug, Clone, Copy)]
pub(crate) struct SuperCall;
impl Operation for SuperCall {
const NAME: &'static str = "SuperCall";
const INSTRUCTION: &'static str = "INST - SuperCall";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u32>();
let mut arguments = Vec::with_capacity(argument_count as usize);
impl SuperCall {
fn operation(context: &mut Context<'_>, argument_count: usize) -> JsResult<CompletionType> {
let mut arguments = Vec::with_capacity(argument_count);
for _ in 0..argument_count {
arguments.push(context.vm.pop());
}
@ -152,6 +148,26 @@ impl Operation for SuperCall {
}
}
impl Operation for SuperCall {
const NAME: &'static str = "SuperCall";
const INSTRUCTION: &'static str = "INST - SuperCall";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u8>() as usize;
Self::operation(context, value_count)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u16>() as usize;
Self::operation(context, value_count)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u32>() as usize;
Self::operation(context, value_count)
}
}
/// `SuperCallSpread` implements the Opcode Operation for `Opcode::SuperCallSpread`
///
/// Operation:

122
boa_engine/src/vm/opcode/get/function.rs

@ -10,17 +10,33 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetArrowFunction;
impl GetArrowFunction {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block.functions[index].clone();
let function = create_function_object_fast(code, false, true, false, context);
context.vm.push(function);
Ok(CompletionType::Normal)
}
}
impl Operation for GetArrowFunction {
const NAME: &'static str = "GetArrowFunction";
const INSTRUCTION: &'static str = "INST - GetArrowFunction";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
context.vm.read::<u8>();
let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_function_object_fast(code, false, true, false, context);
context.vm.push(function);
Ok(CompletionType::Normal)
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
@ -31,17 +47,33 @@ impl Operation for GetArrowFunction {
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetAsyncArrowFunction;
impl GetAsyncArrowFunction {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block.functions[index].clone();
let function = create_function_object_fast(code, true, true, false, context);
context.vm.push(function);
Ok(CompletionType::Normal)
}
}
impl Operation for GetAsyncArrowFunction {
const NAME: &'static str = "GetAsyncArrowFunction";
const INSTRUCTION: &'static str = "INST - GetAsyncArrowFunction";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
context.vm.read::<u8>();
let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_function_object_fast(code, true, true, false, context);
context.vm.push(function);
Ok(CompletionType::Normal)
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
@ -52,17 +84,40 @@ impl Operation for GetAsyncArrowFunction {
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetFunction;
impl GetFunction {
#[allow(clippy::unnecessary_wraps)]
fn operation(
context: &mut Context<'_>,
index: usize,
method: bool,
) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block.functions[index].clone();
let function = create_function_object_fast(code, false, false, method, context);
context.vm.push(function);
Ok(CompletionType::Normal)
}
}
impl Operation for GetFunction {
const NAME: &'static str = "GetFunction";
const INSTRUCTION: &'static str = "INST - GetFunction";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let index = context.vm.read::<u8>() as usize;
let method = context.vm.read::<u8>() != 0;
let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_function_object_fast(code, false, false, method, context);
context.vm.push(function);
Ok(CompletionType::Normal)
Self::operation(context, index, method)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
let method = context.vm.read::<u8>() != 0;
Self::operation(context, index, method)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
let method = context.vm.read::<u8>() != 0;
Self::operation(context, index, method)
}
}
@ -73,16 +128,39 @@ impl Operation for GetFunction {
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetFunctionAsync;
impl GetFunctionAsync {
#[allow(clippy::unnecessary_wraps)]
fn operation(
context: &mut Context<'_>,
index: usize,
method: bool,
) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block.functions[index].clone();
let function = create_function_object_fast(code, true, false, method, context);
context.vm.push(function);
Ok(CompletionType::Normal)
}
}
impl Operation for GetFunctionAsync {
const NAME: &'static str = "GetFunctionAsync";
const INSTRUCTION: &'static str = "INST - GetFunctionAsync";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let index = context.vm.read::<u8>() as usize;
let method = context.vm.read::<u8>() != 0;
let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_function_object_fast(code, true, false, method, context);
context.vm.push(function);
Ok(CompletionType::Normal)
Self::operation(context, index, method)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
let method = context.vm.read::<u8>() != 0;
Self::operation(context, index, method)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
let method = context.vm.read::<u8>() != 0;
Self::operation(context, index, method)
}
}

54
boa_engine/src/vm/opcode/get/generator.rs

@ -10,16 +10,33 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetGenerator;
impl GetGenerator {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block.functions[index].clone();
let function = create_generator_function_object(code, false, None, context);
context.vm.push(function);
Ok(CompletionType::Normal)
}
}
impl Operation for GetGenerator {
const NAME: &'static str = "GetGenerator";
const INSTRUCTION: &'static str = "INST - GetGenerator";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_generator_function_object(code, false, None, context);
context.vm.push(function);
Ok(CompletionType::Normal)
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
@ -30,15 +47,32 @@ impl Operation for GetGenerator {
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetGeneratorAsync;
impl GetGeneratorAsync {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block.functions[index].clone();
let function = create_generator_function_object(code, true, None, context);
context.vm.push(function);
Ok(CompletionType::Normal)
}
}
impl Operation for GetGeneratorAsync {
const NAME: &'static str = "GetGeneratorAsync";
const INSTRUCTION: &'static str = "INST - GetGeneratorAsync";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_generator_function_object(code, true, None, context);
context.vm.push(function);
Ok(CompletionType::Normal)
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}

116
boa_engine/src/vm/opcode/get/name.rs

@ -11,13 +11,9 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetName;
impl Operation for GetName {
const NAME: &'static str = "GetName";
const INSTRUCTION: &'static str = "INST - GetName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
impl GetName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let mut binding_locator = context.vm.frame().code_block.bindings[index];
context.find_runtime_binding(&mut binding_locator)?;
let value = context.get_binding(binding_locator)?.ok_or_else(|| {
let name = context
@ -32,6 +28,26 @@ impl Operation for GetName {
}
}
impl Operation for GetName {
const NAME: &'static str = "GetName";
const INSTRUCTION: &'static str = "INST - GetName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
/// `GetLocator` implements the Opcode Operation for `Opcode::GetLocator`
///
/// Operation:
@ -39,18 +55,34 @@ impl Operation for GetName {
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetLocator;
impl GetLocator {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let mut binding_locator = context.vm.frame().code_block.bindings[index];
context.find_runtime_binding(&mut binding_locator)?;
context.vm.frame_mut().binding_stack.push(binding_locator);
Ok(CompletionType::Normal)
}
}
impl Operation for GetLocator {
const NAME: &'static str = "GetLocator";
const INSTRUCTION: &'static str = "INST - GetLocator";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
context.find_runtime_binding(&mut binding_locator)?;
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
context.vm.frame_mut().binding_stack.push(binding_locator);
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
Ok(CompletionType::Normal)
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
@ -62,13 +94,9 @@ impl Operation for GetLocator {
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetNameAndLocator;
impl Operation for GetNameAndLocator {
const NAME: &'static str = "GetNameAndLocator";
const INSTRUCTION: &'static str = "INST - GetNameAndLocator";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
impl GetNameAndLocator {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let mut binding_locator = context.vm.frame().code_block.bindings[index];
context.find_runtime_binding(&mut binding_locator)?;
let value = context.get_binding(binding_locator)?.ok_or_else(|| {
let name = context
@ -84,6 +112,26 @@ impl Operation for GetNameAndLocator {
}
}
impl Operation for GetNameAndLocator {
const NAME: &'static str = "GetNameAndLocator";
const INSTRUCTION: &'static str = "INST - GetNameAndLocator";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
/// `GetNameOrUndefined` implements the Opcode Operation for `Opcode::GetNameOrUndefined`
///
/// Operation:
@ -91,13 +139,9 @@ impl Operation for GetNameAndLocator {
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetNameOrUndefined;
impl Operation for GetNameOrUndefined {
const NAME: &'static str = "GetNameOrUndefined";
const INSTRUCTION: &'static str = "INST - GetNameOrUndefined";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
impl GetNameOrUndefined {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let mut binding_locator = context.vm.frame().code_block.bindings[index];
let is_global = binding_locator.is_global();
@ -121,3 +165,23 @@ impl Operation for GetNameOrUndefined {
Ok(CompletionType::Normal)
}
}
impl Operation for GetNameOrUndefined {
const NAME: &'static str = "GetNameOrUndefined";
const INSTRUCTION: &'static str = "INST - GetNameOrUndefined";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}

30
boa_engine/src/vm/opcode/get/private.rs

@ -10,13 +10,9 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetPrivateField;
impl Operation for GetPrivateField {
const NAME: &'static str = "GetPrivateField";
const INSTRUCTION: &'static str = "INST - GetPrivateField";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl GetPrivateField {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let value = context.vm.pop();
let base_obj = value.to_object(context)?;
@ -31,3 +27,23 @@ impl Operation for GetPrivateField {
Ok(CompletionType::Normal)
}
}
impl Operation for GetPrivateField {
const NAME: &'static str = "GetPrivateField";
const INSTRUCTION: &'static str = "INST - GetPrivateField";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}

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

@ -1,7 +1,7 @@
use crate::{
property::PropertyKey,
vm::{opcode::Operation, CompletionType},
Context, JsResult, JsValue,
Context, JsResult,
};
/// `GetPropertyByName` implements the Opcode Operation for `Opcode::GetPropertyByName`
@ -11,13 +11,8 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetPropertyByName;
impl Operation for GetPropertyByName {
const NAME: &'static str = "GetPropertyByName";
const INSTRUCTION: &'static str = "INST - GetPropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl GetPropertyByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let receiver = context.vm.pop();
let value = context.vm.pop();
let object = if let Some(object) = value.as_object() {
@ -26,9 +21,7 @@ impl Operation for GetPropertyByName {
value.to_object(context)?
};
let key = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let key = context.vm.frame().code_block.names[index].clone().into();
let result = object.__get__(&key, receiver, context)?;
context.vm.push(result);
@ -36,6 +29,26 @@ impl Operation for GetPropertyByName {
}
}
impl Operation for GetPropertyByName {
const NAME: &'static str = "GetPropertyByName";
const INSTRUCTION: &'static str = "INST - GetPropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
/// `GetPropertyByValue` implements the Opcode Operation for `Opcode::GetPropertyByValue`
///
/// Operation:
@ -82,31 +95,6 @@ impl Operation for GetPropertyByValue {
}
}
/// `GetMethod` implements the Opcode Operation for `Opcode::GetMethod`
///
/// Operation:
/// - Get a property method or undefined if the property is null or undefined.
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetMethod;
impl Operation for GetMethod {
const NAME: &'static str = "GetMethod";
const INSTRUCTION: &'static str = "INST - GetMethod";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let key = context.vm.frame().code_block.names[index as usize].clone();
let value = context.vm.pop();
let method = value.get_method(key, context)?;
context.vm.push(value);
context
.vm
.push(method.map(JsValue::from).unwrap_or_default());
Ok(CompletionType::Normal)
}
}
/// `GetPropertyByValuePush` implements the Opcode Operation for `Opcode::GetPropertyByValuePush`
///
/// Operation:

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

@ -18,6 +18,7 @@ mod generator;
mod get;
mod iteration;
mod meta;
mod modifier;
mod new;
mod nop;
mod pop;
@ -60,6 +61,8 @@ pub(crate) use iteration::*;
#[doc(inline)]
pub(crate) use meta::*;
#[doc(inline)]
pub(crate) use modifier::*;
#[doc(inline)]
pub(crate) use new::*;
#[doc(inline)]
pub(crate) use nop::*;
@ -121,16 +124,86 @@ where
unsafe { read_unchecked(bytes, offset) }
}
/// Represents a varying operand kind.
#[derive(Default, Debug, Clone, Copy)]
pub(crate) enum VaryingOperandKind {
#[default]
U8,
U16,
U32,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct VaryingOperand {
kind: VaryingOperandKind,
value: u32,
}
impl PartialEq for VaryingOperand {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl VaryingOperand {
#[must_use]
pub(crate) fn u8(value: u8) -> Self {
Self {
kind: VaryingOperandKind::U8,
value: u32::from(value),
}
}
#[must_use]
pub(crate) fn u16(value: u16) -> Self {
Self {
kind: VaryingOperandKind::U16,
value: u32::from(value),
}
}
#[must_use]
pub(crate) const fn u32(value: u32) -> Self {
Self {
kind: VaryingOperandKind::U32,
value,
}
}
#[must_use]
pub(crate) const fn value(self) -> u32 {
self.value
}
#[must_use]
pub(crate) const fn kind(self) -> VaryingOperandKind {
self.kind
}
}
trait BytecodeConversion: Sized {
fn to_bytecode(&self, bytes: &mut Vec<u8>);
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self;
fn from_bytecode(bytes: &[u8], pc: &mut usize, varying_kind: VaryingOperandKind) -> Self;
}
impl BytecodeConversion for VaryingOperand {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
match self.kind() {
VaryingOperandKind::U8 => u8::to_bytecode(&(self.value() as u8), bytes),
VaryingOperandKind::U16 => u16::to_bytecode(&(self.value() as u16), bytes),
VaryingOperandKind::U32 => u32::to_bytecode(&self.value(), bytes),
}
}
fn from_bytecode(bytes: &[u8], pc: &mut usize, varying_kind: VaryingOperandKind) -> Self {
match varying_kind {
VaryingOperandKind::U8 => Self::u8(u8::from_bytecode(bytes, pc, varying_kind)),
VaryingOperandKind::U16 => Self::u16(u16::from_bytecode(bytes, pc, varying_kind)),
VaryingOperandKind::U32 => Self::u32(u32::from_bytecode(bytes, pc, varying_kind)),
}
}
}
impl BytecodeConversion for GeneratorResumeKind {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.push(*self as u8);
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<u8>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
JsValue::from(value).to_generator_resume_kind()
@ -141,7 +214,7 @@ impl BytecodeConversion for bool {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.push(u8::from(*self));
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<u8>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value != 0
@ -152,7 +225,7 @@ impl BytecodeConversion for i8 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.push(*self as u8);
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -163,7 +236,7 @@ impl BytecodeConversion for u8 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.push(*self);
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -174,7 +247,7 @@ impl BytecodeConversion for i16 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -185,7 +258,7 @@ impl BytecodeConversion for u16 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -196,7 +269,7 @@ impl BytecodeConversion for i32 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -207,7 +280,7 @@ impl BytecodeConversion for u32 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -218,7 +291,7 @@ impl BytecodeConversion for i64 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -229,7 +302,7 @@ impl BytecodeConversion for u64 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -240,7 +313,7 @@ impl BytecodeConversion for f32 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -251,7 +324,7 @@ impl BytecodeConversion for f64 {
fn to_bytecode(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let value = read::<Self>(bytes, *pc);
*pc += std::mem::size_of::<Self>();
value
@ -265,7 +338,7 @@ impl BytecodeConversion for ThinVec<u32> {
bytes.extend_from_slice(&item.to_ne_bytes());
}
}
fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
fn from_bytecode(bytes: &[u8], pc: &mut usize, _varying_kind: VaryingOperandKind) -> Self {
let count = read::<u32>(bytes, *pc);
*pc += std::mem::size_of::<u32>();
let mut result = Self::with_capacity(count as usize);
@ -302,7 +375,7 @@ macro_rules! generate_opcodes {
/// The opcodes of the vm.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Opcode {
pub(crate) enum Opcode {
$(
$(#[$inner $($args)*])*
$Variant
@ -323,30 +396,36 @@ macro_rules! generate_opcodes {
}
impl Opcode {
const MAX: usize = 2usize.pow(8);
const MAX: usize = 2usize.pow(8) * 3;
const NAMES: [&'static str; Self::MAX] = [
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::NAME),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::NAME),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::NAME),*
];
/// Name of this opcode.
#[must_use]
pub const fn as_str(self) -> &'static str {
pub(crate) const fn as_str(self) -> &'static str {
Self::NAMES[self as usize]
}
const INSTRUCTIONS: [&'static str; Self::MAX] = [
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::INSTRUCTION),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::INSTRUCTION),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::INSTRUCTION),*
];
/// Name of the profiler event for this opcode.
#[must_use]
pub const fn as_instruction_str(self) -> &'static str {
pub(crate) const fn as_instruction_str(self) -> &'static str {
Self::INSTRUCTIONS[self as usize]
}
const EXECUTE_FNS: [fn(&mut Context<'_>) -> JsResult<CompletionType>; Self::MAX] = [
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::execute),*
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::execute),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::execute_with_u16_operands),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::execute_with_u32_operands),*
];
pub(super) fn execute(self, context: &mut Context<'_>) -> JsResult<CompletionType> {
@ -355,15 +434,18 @@ macro_rules! generate_opcodes {
}
/// This represents a VM instruction, it contains both opcode and operands.
///
// TODO: An instruction should be a representation of a valid executable instruction (opcode + operands),
// so variants like `ResevedN`, or operand width prefix modifiers, idealy shouldn't
// be a part of `Instruction`.
#[derive(Debug, Clone, PartialEq)]
#[repr(u8)]
pub enum Instruction {
pub(crate) enum Instruction {
$(
$(#[$inner $($args)*])*
$Variant $({
$(
$(#[$fieldinner $($fieldargs)*])*
#[allow(missing_docs)]
$FieldName : $FieldType
),*
})?
@ -373,7 +455,8 @@ macro_rules! generate_opcodes {
impl Instruction {
/// Convert [`Instruction`] to compact bytecode.
#[inline]
pub fn to_bytecode(&self, bytes: &mut Vec<u8>) {
#[allow(dead_code)]
pub(crate) fn to_bytecode(&self, bytes: &mut Vec<u8>) {
match self {
$(
Self::$Variant $({
@ -395,7 +478,7 @@ macro_rules! generate_opcodes {
/// If the provided bytecode is not valid.
#[inline]
#[must_use]
pub fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self {
pub(crate) fn from_bytecode(bytes: &[u8], pc: &mut usize, varying_kind: VaryingOperandKind) -> Self {
let opcode = bytes[*pc].into();
*pc += 1;
match opcode {
@ -406,7 +489,7 @@ macro_rules! generate_opcodes {
$({
Self::$Variant {
$(
$FieldName: BytecodeConversion::from_bytecode(bytes, pc)
$FieldName: BytecodeConversion::from_bytecode(bytes, pc, varying_kind)
),*
}
})?
@ -422,7 +505,7 @@ macro_rules! generate_opcodes {
/// Get the [`Opcode`] of the [`Instruction`].
#[inline]
#[must_use]
pub const fn opcode(&self) -> Opcode {
pub(crate) const fn opcode(&self) -> Opcode {
match self {
$(
Self::$Variant $({ $( $FieldName: _ ),* })? => Opcode::$Variant
@ -442,7 +525,22 @@ pub(crate) trait Operation {
const NAME: &'static str;
const INSTRUCTION: &'static str;
/// Execute opcode with [`VaryingOperandKind::U8`] sized [`VaryingOperand`]s.
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType>;
/// Execute opcode with [`VaryingOperandKind::U16`] sized [`VaryingOperand`]s.
///
/// By default if not implemented will call [`Reserved::u16_execute()`] which panics.
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
Reserved::execute_with_u16_operands(context)
}
/// Execute opcode with [`VaryingOperandKind::U32`] sized [`VaryingOperand`]s.
///
/// By default if not implemented will call [`Reserved::u32_execute()`] which panics.
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
Reserved::execute_with_u32_operands(context)
}
}
generate_opcodes! {
@ -593,7 +691,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: **=>** (`literals[index]`)
PushLiteral { index: u32 },
PushLiteral { index: VaryingOperand },
/// Push empty object `{}` value on the stack.
///
@ -770,7 +868,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: rhs **=>** (private_name `in` rhs)
InPrivate { index: u32 },
InPrivate { index: VaryingOperand },
/// Binary `==` operator.
///
@ -931,42 +1029,42 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: **=>**
DefVar { index: u32 },
DefVar { index: VaryingOperand },
/// Declare and initialize `var` type variable.
///
/// Operands: index: `u32`
///
/// Stack: value **=>**
DefInitVar { index: u32 },
DefInitVar { index: VaryingOperand },
/// Initialize a lexical binding.
///
/// Operands: index: `u32`
///
/// Stack: value **=>**
PutLexicalValue { index: u32 },
PutLexicalValue { index: VaryingOperand },
/// Throws an error because the binding access is illegal.
///
/// Operands: index: `u32`
///
/// Stack: **=>**
ThrowMutateImmutable { index: u32 },
ThrowMutateImmutable { index: VaryingOperand },
/// Find a binding on the environment chain and push its value.
///
/// Operands: index: `u32`
///
/// Stack: **=>** value
GetName { index: u32 },
GetName { index: VaryingOperand },
/// Find a binding on the environment and set the `current_binding` of the current frame.
///
/// Operands: index: `u32`
///
/// Stack: **=>**
GetLocator { index: u32 },
GetLocator { index: VaryingOperand },
/// Find a binding on the environment chain and push its value to the stack and its
/// `BindingLocator` to the `bindings_stack`.
@ -974,21 +1072,21 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: **=>** value
GetNameAndLocator { index: u32 },
GetNameAndLocator { index: VaryingOperand },
/// Find a binding on the environment chain and push its value. If the binding does not exist push undefined.
///
/// Operands: index: `u32`
///
/// Stack: **=>** value
GetNameOrUndefined { index: u32 },
GetNameOrUndefined { index: VaryingOperand },
/// Find a binding on the environment chain and assign its value.
///
/// Operands: index: `u32`
///
/// Stack: value **=>**
SetName { index: u32 },
SetName { index: VaryingOperand },
/// Assigns a value to the binding pointed by the top of the `bindings_stack`.
///
@ -1000,7 +1098,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: **=>** deleted
DeleteName { index: u32 },
DeleteName { index: VaryingOperand },
/// Get a property by name from an object an push it on the stack.
///
@ -1009,15 +1107,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, receiver **=>** value
GetPropertyByName { index: u32 },
/// Get a property method or undefined if the property is null or undefined.
///
/// Throws if the method is not a callable object.
///
/// Operands: index: `u32`
/// Stack: object **=>** object, method
GetMethod { index: u32 },
GetPropertyByName { index: VaryingOperand },
/// Get a property by value from an object an push it on the stack.
///
@ -1044,7 +1134,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, receiver, value **=>** value
SetPropertyByName { index: u32 },
SetPropertyByName { index: VaryingOperand },
/// Sets the name of a function object.
///
@ -1067,21 +1157,21 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, value **=>**
DefineOwnPropertyByName { index: u32 },
DefineOwnPropertyByName { index: VaryingOperand },
/// Defines a static class method by name.
///
/// Operands: index: `u32`
///
/// Stack: class, function **=>**
DefineClassStaticMethodByName { index: u32 },
DefineClassStaticMethodByName { index: VaryingOperand },
/// Defines a class method by name.
///
/// Operands: index: `u32`
///
/// Stack: class_proto, function **=>**
DefineClassMethodByName { index: u32 },
DefineClassMethodByName { index: VaryingOperand },
/// Sets a property by value of an object.
///
@ -1120,7 +1210,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, value **=>**
SetPropertyGetterByName { index: u32 },
SetPropertyGetterByName { index: VaryingOperand },
/// Defines a static getter class method by name.
///
@ -1129,7 +1219,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: class, binding_function **=>**
DefineClassStaticGetterByName { index: u32 },
DefineClassStaticGetterByName { index: VaryingOperand },
/// Defines a getter class method by name.
///
@ -1138,7 +1228,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: class_proto, function **=>** class
DefineClassGetterByName { index: u32 },
DefineClassGetterByName { index: VaryingOperand },
/// Sets a getter property by value of an object.
///
@ -1174,7 +1264,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, value **=>**
SetPropertySetterByName { index: u32 },
SetPropertySetterByName { index: VaryingOperand },
/// Defines a static setter class method by name.
///
@ -1183,7 +1273,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: class, function **=>**
DefineClassStaticSetterByName { index: u32 },
DefineClassStaticSetterByName { index: VaryingOperand },
/// Defines a setter class method by name.
///
@ -1192,7 +1282,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: class_proto, function **=>**
DefineClassSetterByName { index: u32 },
DefineClassSetterByName { index: VaryingOperand },
/// Sets a setter property by value of an object.
///
@ -1228,7 +1318,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, value **=>** value
SetPrivateField { index: u32 },
SetPrivateField { index: VaryingOperand },
/// Define a private property of a class constructor by it's name.
///
@ -1237,7 +1327,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, value **=>**
DefinePrivateField { index: u32 },
DefinePrivateField { index: VaryingOperand },
/// Set a private method of a class constructor by it's name.
///
@ -1246,7 +1336,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, value **=>**
SetPrivateMethod { index: u32 },
SetPrivateMethod { index: VaryingOperand },
/// Set a private setter property of a class constructor by it's name.
///
@ -1255,7 +1345,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, value **=>**
SetPrivateSetter { index: u32 },
SetPrivateSetter { index: VaryingOperand },
/// Set a private getter property of a class constructor by it's name.
///
@ -1264,7 +1354,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object, value **=>**
SetPrivateGetter { index: u32 },
SetPrivateGetter { index: VaryingOperand },
/// Get a private property by name from an object an push it on the stack.
///
@ -1273,7 +1363,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object **=>** value
GetPrivateField { index: u32 },
GetPrivateField { index: VaryingOperand },
/// Push a field to a class.
///
@ -1287,28 +1377,28 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: class, field_function **=>**
PushClassFieldPrivate { index: u32 },
PushClassFieldPrivate { index: VaryingOperand },
/// Push a private getter to the class.
///
/// Operands: index: `u32`
///
/// Stack: class, getter **=>**
PushClassPrivateGetter { index: u32 },
PushClassPrivateGetter { index: VaryingOperand },
/// Push a private setter to the class.
///
/// Operands: index: `u32`
///
/// Stack: class, setter **=>**
PushClassPrivateSetter { index: u32 },
PushClassPrivateSetter { index: VaryingOperand },
/// Push a private method to the class.
///
/// Operands: index: `u32`
///
/// Stack: class, method **=>**
PushClassPrivateMethod { index: u32 },
PushClassPrivateMethod { index: VaryingOperand },
/// Deletes a property by name of an object.
///
@ -1317,7 +1407,7 @@ generate_opcodes! {
/// Operands: index: `u32`
///
/// Stack: object **=>**
DeletePropertyByName { index: u32 },
DeletePropertyByName { index: VaryingOperand },
/// Deletes a property by value of an object.
///
@ -1337,10 +1427,10 @@ generate_opcodes! {
/// Copy all properties of one object to another object.
///
/// Operands: excluded_key_count: `u32`, excluded_key_count_computed: `u32`
/// Operands: excluded_key_count: `VaryingOperand`, excluded_key_count_computed: `VaryingOperand`
///
/// Stack: excluded_key_computed_0 ... excluded_key_computed_n, source, value, excluded_key_0 ... excluded_key_n **=>** value
CopyDataProperties { excluded_key_count: u32, excluded_key_count_computed: u32 },
CopyDataProperties { excluded_key_count: VaryingOperand, excluded_key_count_computed: VaryingOperand },
/// Call ToPropertyKey on the value on the stack.
///
@ -1448,7 +1538,7 @@ generate_opcodes! {
/// Operands: message: u32
///
/// Stack: **=>**
ThrowNewTypeError { message: u32 },
ThrowNewTypeError { message: VaryingOperand },
/// Pops value converts it to boolean and pushes it back.
///
@ -1483,7 +1573,7 @@ generate_opcodes! {
/// Operands: argument_count: `u32`
///
/// Stack: super_constructor, new_target, argument_1, ... argument_n **=>**
SuperCall { argument_count: u32 },
SuperCall { argument_count: VaryingOperand },
/// Execute the `super()` method where the arguments contain spreads.
///
@ -1523,52 +1613,52 @@ generate_opcodes! {
/// Get arrow function from the pre-compiled inner functions.
///
/// Operands: address: `u32`, method: `u8`
/// Operands: index: `u32`
///
/// Stack: **=>** func
GetArrowFunction { index: u32, method: bool },
GetArrowFunction { index: VaryingOperand },
/// Get async arrow function from the pre-compiled inner functions.
///
/// Operands: index: `u32`, method: `u8`
/// Operands: index: `VaryingOperand`
///
/// Stack: **=>** func
GetAsyncArrowFunction { index: u32, method: bool },
GetAsyncArrowFunction { index: VaryingOperand },
/// Get function from the pre-compiled inner functions.
///
/// Operands: index: `u32`, is_method: `u8`
/// Operands: index: `VaryingOperand`, is_method: `u8`
///
/// Stack: **=>** func
GetFunction { index: u32, method: bool },
GetFunction { index: VaryingOperand, method: bool },
/// Get async function from the pre-compiled inner functions.
///
/// Operands: index: `u32`, method: `u8`
/// Operands: index: `VaryingOperand`, method: `u8`
///
/// Stack: **=>** func
GetFunctionAsync { index: u32, method: bool },
GetFunctionAsync { index: VaryingOperand, method: bool },
/// Get generator function from the pre-compiled inner functions.
///
/// Operands: index: `u32`,
/// Operands: index: `VaryingOperand`,
///
/// Stack: **=>** func
GetGenerator { index: u32 },
GetGenerator { index: VaryingOperand },
/// Get async generator function from the pre-compiled inner functions.
///
/// Operands: index: `u32`,
/// Operands: index: `VaryingOperand`,
///
/// Stack: **=>** func
GetGeneratorAsync { index: u32 },
GetGeneratorAsync { index: VaryingOperand },
/// Call a function named "eval".
///
/// Operands: argument_count: `u32`
/// Operands: argument_count: `VaryingOperand`
///
/// Stack: this, func, argument_1, ... argument_n **=>** result
CallEval { argument_count: u32 },
CallEval { argument_count: VaryingOperand },
/// Call a function named "eval" where the arguments contain spreads.
///
@ -1582,7 +1672,7 @@ generate_opcodes! {
/// Operands: argument_count: `u32`
///
/// Stack: this, func, argument_1, ... argument_n **=>** result
Call { argument_count: u32 },
Call { argument_count: VaryingOperand },
/// Call a function where the arguments contain spreads.
///
@ -1596,7 +1686,7 @@ generate_opcodes! {
/// Operands: argument_count: `u32`
///
/// Stack: func, argument_1, ... argument_n **=>** result
New { argument_count: u32 },
New { argument_count: VaryingOperand },
/// Call construct on a function where the arguments contain spreads.
///
@ -1800,7 +1890,7 @@ generate_opcodes! {
/// Operands: value_count: `u32`
///
/// Stack: `value_1`,...`value_n` **=>** `string`
ConcatToString { value_count: u32 },
ConcatToString { value_count: VaryingOperand },
/// Call RequireObjectCoercible on the stack value.
///
@ -1928,10 +2018,10 @@ generate_opcodes! {
/// Create a new tagged template object and cache it.
///
/// Operands: count: `u32`, site: `u64`
/// Operands: count: `VaryingOperand`, site: `u64`
///
/// Stack: count * (cooked_value, raw_value) **=>** template
TemplateCreate { count: u32, site: u64 },
TemplateCreate { count: VaryingOperand, site: u64 },
/// Push a private environment.
///
@ -1954,6 +2044,20 @@ generate_opcodes! {
/// Stack: **=>**
Nop,
/// Opcode prefix modifier, makes all [`VaryingOperand`]s of an instruction [`u16`] sized.
///
/// Operands: opcode (operands if any).
///
/// Stack: The stack changes based on the opcode that is being prefixed.
U16Operands,
/// Opcode prefix modifier, [`Opcode`] prefix operand modifier, makes all [`VaryingOperand`]s of an instruction [`u32`] sized.
///
/// Operands: opcode (operands if any).
///
/// Stack: The stack changes based on the opcode that is being prefixed.
U32Operands,
/// Reserved [`Opcode`].
Reserved1 => Reserved,
/// Reserved [`Opcode`].
@ -2068,8 +2172,6 @@ generate_opcodes! {
Reserved56 => Reserved,
/// Reserved [`Opcode`].
Reserved57 => Reserved,
/// Reserved [`Opcode`].
Reserved58 => Reserved,
}
/// Specific opcodes for bindings.
@ -2086,7 +2188,7 @@ pub(crate) enum BindingOpcode {
/// Iterator over the instructions in the compact bytecode.
#[derive(Debug, Clone)]
pub struct InstructionIterator<'bytecode> {
pub(crate) struct InstructionIterator<'bytecode> {
bytes: &'bytecode [u8],
pc: usize,
}
@ -2095,21 +2197,52 @@ impl<'bytecode> InstructionIterator<'bytecode> {
/// Create a new [`InstructionIterator`] from bytecode array.
#[inline]
#[must_use]
pub const fn new(bytes: &'bytecode [u8]) -> Self {
pub(crate) const fn new(bytes: &'bytecode [u8]) -> Self {
Self { bytes, pc: 0 }
}
/// Create a new [`InstructionIterator`] from bytecode array at pc.
#[inline]
#[must_use]
pub(crate) const fn with_pc(bytes: &'bytecode [u8], pc: usize) -> Self {
Self { bytes, pc }
}
/// Return the current program counter.
#[must_use]
pub(crate) const fn pc(&self) -> usize {
self.pc
}
}
impl Iterator for InstructionIterator<'_> {
type Item = Instruction;
type Item = (usize, VaryingOperandKind, Instruction);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let start_pc = self.pc;
if self.pc >= self.bytes.len() {
return None;
}
Some(Instruction::from_bytecode(self.bytes, &mut self.pc))
let instruction =
Instruction::from_bytecode(self.bytes, &mut self.pc, VaryingOperandKind::U8);
if instruction == Instruction::U16Operands {
return Some((
start_pc,
VaryingOperandKind::U16,
Instruction::from_bytecode(self.bytes, &mut self.pc, VaryingOperandKind::U16),
));
} else if instruction == Instruction::U32Operands {
return Some((
start_pc,
VaryingOperandKind::U32,
Instruction::from_bytecode(self.bytes, &mut self.pc, VaryingOperandKind::U32),
));
}
Some((start_pc, VaryingOperandKind::U8, instruction))
}
}

39
boa_engine/src/vm/opcode/modifier.rs

@ -0,0 +1,39 @@
use crate::{vm::CompletionType, Context, JsResult};
use super::{Opcode, Operation};
/// `U16Operands` implements the Opcode Operation for `Opcode::U16Operands`
///
/// Operation:
/// - [`Opcode`] prefix operand modifier, makes all varying operands of an instruction [`u16`] sized.
#[derive(Debug, Clone, Copy)]
pub(crate) struct U16Operands;
impl Operation for U16Operands {
const NAME: &'static str = "U16Operands";
const INSTRUCTION: &'static str = "INST - U16Operands";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let opcode = context.vm.read::<u8>() as usize;
Opcode::EXECUTE_FNS[256 + opcode](context)
}
}
/// `U32Operands` implements the Opcode Operation for `Opcode::U32Operands`
///
/// Operation:
/// - [`Opcode`] prefix operand modifier, makes all varying operands of an instruction [`u32`] sized.
#[derive(Debug, Clone, Copy)]
pub(crate) struct U32Operands;
impl Operation for U32Operands {
const NAME: &'static str = "U32Operands";
const INSTRUCTION: &'static str = "INST - U32Operands";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let opcode = context.vm.read::<u8>() as usize;
Opcode::EXECUTE_FNS[256 * 2 + opcode](context)
}
}

30
boa_engine/src/vm/opcode/new/mod.rs

@ -11,11 +11,8 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct New;
impl Operation for New {
const NAME: &'static str = "New";
const INSTRUCTION: &'static str = "INST - New";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
impl New {
fn operation(context: &mut Context<'_>, argument_count: usize) -> JsResult<CompletionType> {
if context.vm.runtime_limits.recursion_limit() <= context.vm.frames.len() {
return Err(JsNativeError::runtime_limit()
.with_message(format!(
@ -29,8 +26,7 @@ impl Operation for New {
.with_message("Maximum call stack size exceeded")
.into());
}
let argument_count = context.vm.read::<u32>();
let mut arguments = Vec::with_capacity(argument_count as usize);
let mut arguments = Vec::with_capacity(argument_count);
for _ in 0..argument_count {
arguments.push(context.vm.pop());
}
@ -51,6 +47,26 @@ impl Operation for New {
}
}
impl Operation for New {
const NAME: &'static str = "New";
const INSTRUCTION: &'static str = "INST - New";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u8>() as usize;
Self::operation(context, argument_count)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u16>() as usize;
Self::operation(context, argument_count)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u32>() as usize;
Self::operation(context, argument_count)
}
}
/// `NewSpread` implements the Opcode Operation for `Opcode::NewSpread`
///
/// Operation:

8
boa_engine/src/vm/opcode/nop/mod.rs

@ -33,4 +33,12 @@ impl Operation for Reserved {
fn execute(_: &mut Context<'_>) -> JsResult<CompletionType> {
unreachable!("Reserved opcodes are unreachable!")
}
fn execute_with_u16_operands(_: &mut Context<'_>) -> JsResult<CompletionType> {
unreachable!("Reserved.U16 opcodes are unreachable!")
}
fn execute_with_u32_operands(_: &mut Context<'_>) -> JsResult<CompletionType> {
unreachable!("Reserved.U32 opcodes are unreachable!")
}
}

31
boa_engine/src/vm/opcode/push/class/field.rs

@ -52,13 +52,10 @@ impl Operation for PushClassField {
#[derive(Debug, Clone, Copy)]
pub(crate) struct PushClassFieldPrivate;
impl Operation for PushClassFieldPrivate {
const NAME: &'static str = "PushClassFieldPrivate";
const INSTRUCTION: &'static str = "INST - PushClassFieldPrivate";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl PushClassFieldPrivate {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let field_function_value = context.vm.pop();
let class_value = context.vm.pop();
@ -86,3 +83,23 @@ impl Operation for PushClassFieldPrivate {
Ok(CompletionType::Normal)
}
}
impl Operation for PushClassFieldPrivate {
const NAME: &'static str = "PushClassFieldPrivate";
const INSTRUCTION: &'static str = "INST - PushClassFieldPrivate";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}

93
boa_engine/src/vm/opcode/push/class/private.rs

@ -14,13 +14,10 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct PushClassPrivateMethod;
impl Operation for PushClassPrivateMethod {
const NAME: &'static str = "PushClassPrivateMethod";
const INSTRUCTION: &'static str = "INST - PushClassPrivateMethod";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl PushClassPrivateMethod {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let method = context.vm.pop();
let method_object = method.as_callable().expect("method must be callable");
@ -56,6 +53,26 @@ impl Operation for PushClassPrivateMethod {
}
}
impl Operation for PushClassPrivateMethod {
const NAME: &'static str = "PushClassPrivateMethod";
const INSTRUCTION: &'static str = "INST - PushClassPrivateMethod";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `PushClassPrivateGetter` implements the Opcode Operation for `Opcode::PushClassPrivateGetter`
///
/// Operation:
@ -63,13 +80,10 @@ impl Operation for PushClassPrivateMethod {
#[derive(Debug, Clone, Copy)]
pub(crate) struct PushClassPrivateGetter;
impl Operation for PushClassPrivateGetter {
const NAME: &'static str = "PushClassPrivateGetter";
const INSTRUCTION: &'static str = "INST - PushClassPrivateGetter";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl PushClassPrivateGetter {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let getter = context.vm.pop();
let getter_object = getter.as_callable().expect("getter must be callable");
let class = context.vm.pop();
@ -95,6 +109,26 @@ impl Operation for PushClassPrivateGetter {
}
}
impl Operation for PushClassPrivateGetter {
const NAME: &'static str = "PushClassPrivateGetter";
const INSTRUCTION: &'static str = "INST - PushClassPrivateGetter";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `PushClassPrivateSetter` implements the Opcode Operation for `Opcode::PushClassPrivateSetter`
///
/// Operation:
@ -102,13 +136,10 @@ impl Operation for PushClassPrivateGetter {
#[derive(Debug, Clone, Copy)]
pub(crate) struct PushClassPrivateSetter;
impl Operation for PushClassPrivateSetter {
const NAME: &'static str = "PushClassPrivateSetter";
const INSTRUCTION: &'static str = "INST - PushClassPrivateSetter";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl PushClassPrivateSetter {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let setter = context.vm.pop();
let setter_object = setter.as_callable().expect("getter must be callable");
let class = context.vm.pop();
@ -133,3 +164,23 @@ impl Operation for PushClassPrivateSetter {
Ok(CompletionType::Normal)
}
}
impl Operation for PushClassPrivateSetter {
const NAME: &'static str = "PushClassPrivateSetter";
const INSTRUCTION: &'static str = "INST - PushClassPrivateSetter";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}

25
boa_engine/src/vm/opcode/push/literal.rs

@ -10,14 +10,31 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct PushLiteral;
impl PushLiteral {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let value = context.vm.frame().code_block.literals[index].clone();
context.vm.push(value);
Ok(CompletionType::Normal)
}
}
impl Operation for PushLiteral {
const NAME: &'static str = "PushLiteral";
const INSTRUCTION: &'static str = "INST - PushLiteral";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
let value = context.vm.frame().code_block.literals[index].clone();
context.vm.push(value);
Ok(CompletionType::Normal)
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}

60
boa_engine/src/vm/opcode/set/name.rs

@ -11,13 +11,9 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct ThrowMutateImmutable;
impl Operation for ThrowMutateImmutable {
const NAME: &'static str = "ThrowMutateImmutable";
const INSTRUCTION: &'static str = "INST - ThrowMutateImmutable";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = &context.vm.frame().code_block.names[index as usize];
impl ThrowMutateImmutable {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = &context.vm.frame().code_block.names[index];
Err(JsNativeError::typ()
.with_message(format!(
@ -28,6 +24,26 @@ impl Operation for ThrowMutateImmutable {
}
}
impl Operation for ThrowMutateImmutable {
const NAME: &'static str = "ThrowMutateImmutable";
const INSTRUCTION: &'static str = "INST - ThrowMutateImmutable";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
/// `SetName` implements the Opcode Operation for `Opcode::SetName`
///
/// Operation:
@ -35,13 +51,9 @@ impl Operation for ThrowMutateImmutable {
#[derive(Debug, Clone, Copy)]
pub(crate) struct SetName;
impl Operation for SetName {
const NAME: &'static str = "SetName";
const INSTRUCTION: &'static str = "INST - SetName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize];
impl SetName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let mut binding_locator = context.vm.frame().code_block.bindings[index];
let value = context.vm.pop();
context.find_runtime_binding(&mut binding_locator)?;
@ -58,6 +70,26 @@ impl Operation for SetName {
}
}
impl Operation for SetName {
const NAME: &'static str = "SetName";
const INSTRUCTION: &'static str = "INST - SetName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
/// `SetNameByLocator` implements the Opcode Operation for `Opcode::SetNameByLocator`
///
/// Operation:

154
boa_engine/src/vm/opcode/set/private.rs

@ -14,13 +14,9 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct SetPrivateField;
impl Operation for SetPrivateField {
const NAME: &'static str = "SetPrivateField";
const INSTRUCTION: &'static str = "INST - SetPrivateField";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl SetPrivateField {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let value = context.vm.pop();
let object = context.vm.pop();
let base_obj = object.to_object(context)?;
@ -37,6 +33,26 @@ impl Operation for SetPrivateField {
}
}
impl Operation for SetPrivateField {
const NAME: &'static str = "SetPrivateField";
const INSTRUCTION: &'static str = "INST - SetPrivateField";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `DefinePrivateField` implements the Opcode Operation for `Opcode::DefinePrivateField`
///
/// Operation:
@ -44,13 +60,10 @@ impl Operation for SetPrivateField {
#[derive(Debug, Clone, Copy)]
pub(crate) struct DefinePrivateField;
impl Operation for DefinePrivateField {
const NAME: &'static str = "DefinePrivateField";
const INSTRUCTION: &'static str = "INST - DefinePrivateField";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl DefinePrivateField {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let value = context.vm.pop();
let object = context.vm.pop();
let object = object
@ -65,6 +78,26 @@ impl Operation for DefinePrivateField {
}
}
impl Operation for DefinePrivateField {
const NAME: &'static str = "DefinePrivateField";
const INSTRUCTION: &'static str = "INST - DefinePrivateField";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `SetPrivateMethod` implements the Opcode Operation for `Opcode::SetPrivateMethod`
///
/// Operation:
@ -72,13 +105,10 @@ impl Operation for DefinePrivateField {
#[derive(Debug, Clone, Copy)]
pub(crate) struct SetPrivateMethod;
impl Operation for SetPrivateMethod {
const NAME: &'static str = "SetPrivateMethod";
const INSTRUCTION: &'static str = "INST - SetPrivateMethod";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl SetPrivateMethod {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let value = context.vm.pop();
let value = value.as_callable().expect("method must be callable");
@ -112,6 +142,26 @@ impl Operation for SetPrivateMethod {
}
}
impl Operation for SetPrivateMethod {
const NAME: &'static str = "SetPrivateMethod";
const INSTRUCTION: &'static str = "INST - SetPrivateMethod";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `SetPrivateSetter` implements the Opcode Operation for `Opcode::SetPrivateSetter`
///
/// Operation:
@ -119,13 +169,10 @@ impl Operation for SetPrivateMethod {
#[derive(Debug, Clone, Copy)]
pub(crate) struct SetPrivateSetter;
impl Operation for SetPrivateSetter {
const NAME: &'static str = "SetPrivateSetter";
const INSTRUCTION: &'static str = "INST - SetPrivateSetter";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl SetPrivateSetter {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let value = context.vm.pop();
let value = value.as_callable().expect("setter must be callable");
let object = context.vm.pop();
@ -150,6 +197,26 @@ impl Operation for SetPrivateSetter {
}
}
impl Operation for SetPrivateSetter {
const NAME: &'static str = "SetPrivateSetter";
const INSTRUCTION: &'static str = "INST - SetPrivateSetter";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `SetPrivateGetter` implements the Opcode Operation for `Opcode::SetPrivateGetter`
///
/// Operation:
@ -157,13 +224,10 @@ impl Operation for SetPrivateSetter {
#[derive(Debug, Clone, Copy)]
pub(crate) struct SetPrivateGetter;
impl Operation for SetPrivateGetter {
const NAME: &'static str = "SetPrivateGetter";
const INSTRUCTION: &'static str = "INST - SetPrivateGetter";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = context.vm.frame().code_block.names[index as usize].clone();
impl SetPrivateGetter {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
let value = context.vm.pop();
let value = value.as_callable().expect("getter must be callable");
let object = context.vm.pop();
@ -187,3 +251,23 @@ impl Operation for SetPrivateGetter {
Ok(CompletionType::Normal)
}
}
impl Operation for SetPrivateGetter {
const NAME: &'static str = "SetPrivateGetter";
const INSTRUCTION: &'static str = "INST - SetPrivateGetter";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}

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

@ -14,13 +14,8 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub(crate) struct SetPropertyByName;
impl Operation for SetPropertyByName {
const NAME: &'static str = "SetPropertyByName";
const INSTRUCTION: &'static str = "INST - SetPropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl SetPropertyByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let value = context.vm.pop();
let receiver = context.vm.pop();
let object = context.vm.pop();
@ -30,9 +25,7 @@ impl Operation for SetPropertyByName {
object.to_object(context)?
};
let name: PropertyKey = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let name: PropertyKey = context.vm.frame().code_block.names[index].clone().into();
let succeeded = object.__set__(name.clone(), value.clone(), receiver, context)?;
if !succeeded && context.vm.frame().code_block.strict() {
@ -45,6 +38,26 @@ impl Operation for SetPropertyByName {
}
}
impl Operation for SetPropertyByName {
const NAME: &'static str = "SetPropertyByName";
const INSTRUCTION: &'static str = "INST - SetPropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
Self::operation(context, index as usize)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
Self::operation(context, index as usize)
}
}
/// `SetPropertyByValue` implements the Opcode Operation for `Opcode::SetPropertyByValue`
///
/// Operation:
@ -156,18 +169,12 @@ impl Operation for SetPropertyByValue {
#[derive(Debug, Clone, Copy)]
pub(crate) struct SetPropertyGetterByName;
impl Operation for SetPropertyGetterByName {
const NAME: &'static str = "SetPropertyGetterByName";
const INSTRUCTION: &'static str = "INST - SetPropertyGetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl SetPropertyGetterByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let value = context.vm.pop();
let object = context.vm.pop();
let object = object.to_object(context)?;
let name = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let name = context.vm.frame().code_block.names[index].clone().into();
let set = object
.__get_own_property__(&name, context)?
.as_ref()
@ -187,6 +194,26 @@ impl Operation for SetPropertyGetterByName {
}
}
impl Operation for SetPropertyGetterByName {
const NAME: &'static str = "SetPropertyGetterByName";
const INSTRUCTION: &'static str = "INST - SetPropertyGetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `SetPropertyGetterByValue` implements the Opcode Operation for `Opcode::SetPropertyGetterByValue`
///
/// Operation:
@ -230,18 +257,12 @@ impl Operation for SetPropertyGetterByValue {
#[derive(Debug, Clone, Copy)]
pub(crate) struct SetPropertySetterByName;
impl Operation for SetPropertySetterByName {
const NAME: &'static str = "SetPropertySetterByName";
const INSTRUCTION: &'static str = "INST - SetPropertySetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
impl SetPropertySetterByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let value = context.vm.pop();
let object = context.vm.pop();
let object = object.to_object(context)?;
let name = context.vm.frame().code_block.names[index as usize]
.clone()
.into();
let name = context.vm.frame().code_block.names[index].clone().into();
let get = object
.__get_own_property__(&name, context)?
.as_ref()
@ -261,6 +282,26 @@ impl Operation for SetPropertySetterByName {
}
}
impl Operation for SetPropertySetterByName {
const NAME: &'static str = "SetPropertySetterByName";
const INSTRUCTION: &'static str = "INST - SetPropertySetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `SetPropertySetterByValue` implements the Opcode Operation for `Opcode::SetPropertySetterByValue`
///
/// Operation:

34
boa_engine/src/vm/opcode/templates/mod.rs

@ -38,14 +38,9 @@ impl Operation for TemplateLookup {
#[derive(Debug, Clone, Copy)]
pub(crate) struct TemplateCreate;
impl Operation for TemplateCreate {
const NAME: &'static str = "TemplateCreate";
const INSTRUCTION: &'static str = "INST - TemplateCreate";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let count = context.vm.read::<u32>();
let site = context.vm.read::<u64>();
impl TemplateCreate {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, count: u32, site: u64) -> JsResult<CompletionType> {
let template =
Array::array_create(count.into(), None, context).expect("cannot fail per spec");
let raw_obj =
@ -102,3 +97,26 @@ impl Operation for TemplateCreate {
Ok(CompletionType::Normal)
}
}
impl Operation for TemplateCreate {
const NAME: &'static str = "TemplateCreate";
const INSTRUCTION: &'static str = "INST - TemplateCreate";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let count = u32::from(context.vm.read::<u8>());
let site = context.vm.read::<u64>();
Self::operation(context, count, site)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let count = u32::from(context.vm.read::<u16>());
let site = context.vm.read::<u64>();
Self::operation(context, count, site)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let count = context.vm.read::<u32>();
let site = context.vm.read::<u64>();
Self::operation(context, count, site)
}
}

Loading…
Cancel
Save