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

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

@ -40,7 +40,10 @@ impl ByteCompiler<'_, '_> {
match name { match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
let index = self.get_or_insert_name((*name).into()); 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) => { PropertyName::Computed(node) => {
self.compile_expr(node, true); self.compile_expr(node, true);
@ -81,8 +84,8 @@ impl ByteCompiler<'_, '_> {
self.emit( self.emit(
Opcode::CopyDataProperties, Opcode::CopyDataProperties,
&[ &[
Operand::U32(excluded_keys.len() as u32), Operand::Varying(excluded_keys.len() as u32),
Operand::U32(additional_excluded_keys_count), Operand::Varying(additional_excluded_keys_count),
], ],
); );
self.emit_binding(def, *ident); self.emit_binding(def, *ident);
@ -100,7 +103,10 @@ impl ByteCompiler<'_, '_> {
} }
self.emit( self.emit(
Opcode::CopyDataProperties, 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( self.access_set(
Access::Property { access }, Access::Property { access },
@ -118,7 +124,10 @@ impl ByteCompiler<'_, '_> {
match name { match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
let index = self.get_or_insert_name((*name).into()); 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) => { PropertyName::Computed(node) => {
self.compile_expr(node, true); self.compile_expr(node, true);
@ -158,7 +167,10 @@ impl ByteCompiler<'_, '_> {
match name { match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
let index = self.get_or_insert_name((*name).into()); 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) => { PropertyName::Computed(node) => {
self.compile_expr(node, true); 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 binding = self.initialize_mutable_binding(f, true);
let index = self.get_or_insert_binding(binding); let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined); 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; let index = self.functions.len() as u32;
self.functions.push(code); self.functions.push(code);
if r#async && generator { if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator { } else if generator {
self.emit(Opcode::GetGenerator, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async { } else if r#async {
self.emit( self.emit(
Opcode::GetFunctionAsync, Opcode::GetFunctionAsync,
&[Operand::U32(index), Operand::Bool(false)], &[Operand::Varying(index), Operand::Bool(false)],
); );
} else { } else {
self.emit( self.emit(
Opcode::GetFunction, 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) { match self.set_mutable_binding(name) {
Ok(binding) => { Ok(binding) => {
let index = self.get_or_insert_binding(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) => { Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name); 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) => { Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
@ -761,7 +761,7 @@ impl ByteCompiler<'_, '_> {
self.create_mutable_binding(name, !strict); self.create_mutable_binding(name, !strict);
let binding = self.initialize_mutable_binding(name, !strict); let binding = self.initialize_mutable_binding(name, !strict);
let index = self.get_or_insert_binding(binding); 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 binding = self.initialize_mutable_binding(name, !strict);
let index = self.get_or_insert_binding(binding); let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined); 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). // a. Let initialValue be ! env.GetBindingValue(n, false).
let binding = self.get_binding_value(n); let binding = self.get_binding_value(n);
let index = self.get_or_insert_binding(binding); 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). // 5. Perform ! varEnv.InitializeBinding(n, initialValue).
let binding = self.initialize_mutable_binding(n, true); let binding = self.initialize_mutable_binding(n, true);
let index = self.get_or_insert_binding(binding); let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined); 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 // 6. NOTE: A var with the same name as a formal parameter initially has
// the same value as the corresponding initialized parameter. // the same value as the corresponding initialized parameter.
@ -1090,7 +1090,7 @@ impl ByteCompiler<'_, '_> {
let binding = self.initialize_mutable_binding(n, true); let binding = self.initialize_mutable_binding(n, true);
let index = self.get_or_insert_binding(binding); let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined); 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 binding = self.initialize_mutable_binding(f, true);
let index = self.get_or_insert_binding(binding); let index = self.get_or_insert_binding(binding);
self.emit_opcode(Opcode::PushUndefined); 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. // c. Append F to instantiatedVarNames.
instantiated_var_names.push(f); 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); let lex = self.current_environment.is_lex_binding(name);
if lex { if lex {
self.emit(Opcode::GetName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetName, index);
} else { } else {
self.emit(Opcode::GetNameAndLocator, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetNameAndLocator, index);
} }
if short_circuit { if short_circuit {
@ -79,11 +79,11 @@ impl ByteCompiler<'_, '_> {
match self.set_mutable_binding(name) { match self.set_mutable_binding(name) {
Ok(binding) => { Ok(binding) => {
let index = self.get_or_insert_binding(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) => { Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name); 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) => { Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
@ -102,7 +102,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
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 { if short_circuit {
pop_count = 2; pop_count = 2;
early_exit = Some(self.emit_opcode_with_operand(opcode)); early_exit = Some(self.emit_opcode_with_operand(opcode));
@ -112,7 +112,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(opcode); self.emit_opcode(opcode);
} }
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if !use_expr { if !use_expr {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }
@ -145,7 +145,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPrivateField, index);
if short_circuit { if short_circuit {
pop_count = 1; pop_count = 1;
early_exit = Some(self.emit_opcode_with_operand(opcode)); early_exit = Some(self.emit_opcode_with_operand(opcode));
@ -155,7 +155,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(opcode); self.emit_opcode(opcode);
} }
self.emit(Opcode::SetPrivateField, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::SetPrivateField, index);
if !use_expr { if !use_expr {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }
@ -169,7 +169,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Swap); self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::This); self.emit_opcode(Opcode::This);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
if short_circuit { if short_circuit {
pop_count = 2; pop_count = 2;
early_exit = Some(self.emit_opcode_with_operand(opcode)); early_exit = Some(self.emit_opcode_with_operand(opcode));
@ -179,7 +179,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(opcode); self.emit_opcode(opcode);
} }
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if !use_expr { if !use_expr {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }

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

@ -3,10 +3,7 @@ use boa_ast::expression::operator::{
Binary, BinaryInPrivate, Binary, BinaryInPrivate,
}; };
use crate::{ use crate::{bytecompiler::ByteCompiler, vm::Opcode};
bytecompiler::{ByteCompiler, Operand},
vm::Opcode,
};
impl ByteCompiler<'_, '_> { impl ByteCompiler<'_, '_> {
pub(crate) fn compile_binary(&mut self, binary: &Binary, use_expr: bool) { 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) { pub(crate) fn compile_binary_in_private(&mut self, binary: &BinaryInPrivate, use_expr: bool) {
let index = self.get_or_insert_private_name(*binary.lhs()); let index = self.get_or_insert_private_name(*binary.lhs());
self.compile_expr(binary.rhs(), true); self.compile_expr(binary.rhs(), true);
self.emit(Opcode::InPrivate, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::InPrivate, index);
if !use_expr { if !use_expr {
self.emit_opcode(Opcode::Pop); 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, Opcode::ConcatToString,
&[Operand::U32(template_literal.elements().len() as u32)], template_literal.elements().len() as u32,
); );
if !use_expr { if !use_expr {
@ -228,7 +228,7 @@ impl ByteCompiler<'_, '_> {
match access.field() { match access.field() {
PropertyAccessField::Const(field) => { PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into()); let index = self.get_or_insert_name((*field).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
} }
PropertyAccessField::Expr(field) => { PropertyAccessField::Expr(field) => {
self.compile_expr(field, true); self.compile_expr(field, true);
@ -240,7 +240,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit(Opcode::Dup, &[]); self.emit(Opcode::Dup, &[]);
let index = self.get_or_insert_private_name(access.field()); 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 => { expr => {
self.emit_opcode(Opcode::PushUndefined); self.emit_opcode(Opcode::PushUndefined);
@ -267,8 +267,10 @@ impl ByteCompiler<'_, '_> {
)); ));
} }
self.emit(Opcode::TemplateCreate, &[Operand::U32(count)]); self.emit(
self.emit_u64(site); Opcode::TemplateCreate,
&[Operand::Varying(count), Operand::U64(site)],
);
self.patch_jump(jump_label); self.patch_jump(jump_label);
@ -276,10 +278,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(expr, true); self.compile_expr(expr, true);
} }
self.emit( self.emit_with_varying_operand(Opcode::Call, template.exprs().len() as u32 + 1);
Opcode::Call,
&[Operand::U32(template.exprs().len() as u32 + 1)],
);
} }
Expression::Class(class) => self.class(class, true), Expression::Class(class) => self.class(class, true),
Expression::SuperCall(super_call) => { Expression::SuperCall(super_call) => {
@ -310,9 +309,9 @@ impl ByteCompiler<'_, '_> {
if contains_spread { if contains_spread {
self.emit_opcode(Opcode::SuperCallSpread); self.emit_opcode(Opcode::SuperCallSpread);
} else { } else {
self.emit( self.emit_with_varying_operand(
Opcode::SuperCall, 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) => { PropertyDefinition::IdentifierReference(ident) => {
let index = self.get_or_insert_name(*ident); let index = self.get_or_insert_name(*ident);
self.access_get(Access::Variable { name: *ident }, true); 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 { PropertyDefinition::Property(name, expr) => match name {
PropertyName::Literal(name) => { PropertyName::Literal(name) => {
@ -27,7 +27,7 @@ impl ByteCompiler<'_, '_> {
if *name == Sym::__PROTO__ && !self.json_parse { if *name == Sym::__PROTO__ && !self.json_parse {
self.emit_opcode(Opcode::SetPrototype); self.emit_opcode(Opcode::SetPrototype);
} else { } else {
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
} }
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
@ -49,7 +49,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertyGetterByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::SetPropertyGetterByName, index);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method( self.compile_object_literal_computed_method(
@ -64,7 +64,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertySetterByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::SetPropertySetterByName, index);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method( self.compile_object_literal_computed_method(
@ -79,7 +79,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method( self.compile_object_literal_computed_method(
@ -94,7 +94,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method( self.compile_object_literal_computed_method(
@ -109,7 +109,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method( self.compile_object_literal_computed_method(
@ -124,7 +124,7 @@ impl ByteCompiler<'_, '_> {
self.object_method(expr.into()); self.object_method(expr.into());
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index);
} }
PropertyName::Computed(name_node) => { PropertyName::Computed(name_node) => {
self.compile_object_literal_computed_method( self.compile_object_literal_computed_method(
@ -140,7 +140,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Swap); self.emit_opcode(Opcode::Swap);
self.emit( self.emit(
Opcode::CopyDataProperties, Opcode::CopyDataProperties,
&[Operand::U32(0), Operand::U32(0)], &[Operand::Varying(0), Operand::Varying(0)],
); );
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }

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

@ -4,7 +4,7 @@ use boa_ast::{
}; };
use crate::{ use crate::{
bytecompiler::{Access, ByteCompiler, Operand}, bytecompiler::{Access, ByteCompiler},
vm::Opcode, vm::Opcode,
}; };
@ -29,7 +29,7 @@ impl ByteCompiler<'_, '_> {
Expression::Identifier(identifier) => { Expression::Identifier(identifier) => {
let binding = self.get_binding_value(*identifier); let binding = self.get_binding_value(*identifier);
let index = self.get_or_insert_binding(binding); 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), 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); let lex = self.current_environment.is_lex_binding(name);
if lex { if lex {
self.emit(Opcode::GetName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetName, index);
} else { } else {
self.emit(Opcode::GetNameAndLocator, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetNameAndLocator, index);
} }
self.emit_opcode(opcode); self.emit_opcode(opcode);
@ -44,11 +44,11 @@ impl ByteCompiler<'_, '_> {
match self.set_mutable_binding(name) { match self.set_mutable_binding(name) {
Ok(binding) => { Ok(binding) => {
let index = self.get_or_insert_binding(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) => { Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name); 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) => { Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
@ -67,13 +67,13 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
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); self.emit_opcode(opcode);
if post { if post {
self.emit(Opcode::RotateRight, &[Operand::U8(4)]); self.emit(Opcode::RotateRight, &[Operand::U8(4)]);
} }
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if post { if post {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }
@ -102,13 +102,13 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPrivateField, index);
self.emit_opcode(opcode); self.emit_opcode(opcode);
if post { if post {
self.emit(Opcode::RotateRight, &[Operand::U8(3)]); self.emit(Opcode::RotateRight, &[Operand::U8(3)]);
} }
self.emit(Opcode::SetPrivateField, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::SetPrivateField, index);
if post { if post {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }
@ -122,13 +122,13 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Swap); self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::This); self.emit_opcode(Opcode::This);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
self.emit_opcode(opcode); self.emit_opcode(opcode);
if post { if post {
self.emit(Opcode::RotateRight, &[Operand::U8(3)]); self.emit(Opcode::RotateRight, &[Operand::U8(3)]);
} }
self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::SetPropertyByName, index);
if post { if post {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }

173
boa_engine/src/bytecompiler/mod.rs

@ -17,7 +17,10 @@ use crate::{
builtins::function::ThisMode, builtins::function::ThisMode,
environments::{BindingLocator, BindingLocatorError, CompileTimeEnvironment}, environments::{BindingLocator, BindingLocatorError, CompileTimeEnvironment},
js_string, js_string,
vm::{BindingOpcode, CodeBlock, CodeBlockFlags, GeneratorResumeKind, Handler, Opcode}, vm::{
BindingOpcode, CodeBlock, CodeBlockFlags, GeneratorResumeKind, Handler, Opcode,
VaryingOperandKind,
},
Context, JsBigInt, JsString, JsValue, Context, JsBigInt, JsString, JsValue,
}; };
use boa_ast::{ use boa_ast::{
@ -223,6 +226,7 @@ pub(crate) enum Operand {
U32(u32), U32(u32),
I64(i64), I64(i64),
U64(u64), U64(u64),
Varying(u32),
} }
/// The [`ByteCompiler`] is used to compile ECMAScript AST from [`boa_ast`] to bytecode. /// 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 => { BindingOpcode::Var => {
let binding = self.initialize_mutable_binding(name, true); let binding = self.initialize_mutable_binding(name, true);
let index = self.get_or_insert_binding(binding); 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 => { BindingOpcode::InitVar => {
if self.has_binding(name) { if self.has_binding(name) {
match self.set_mutable_binding(name) { match self.set_mutable_binding(name) {
Ok(binding) => { Ok(binding) => {
let index = self.get_or_insert_binding(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) => { Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name); 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) => { Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
@ -426,27 +430,27 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
} else { } else {
let binding = self.initialize_mutable_binding(name, true); let binding = self.initialize_mutable_binding(name, true);
let index = self.get_or_insert_binding(binding); 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 => { BindingOpcode::InitLet => {
let binding = self.initialize_mutable_binding(name, false); let binding = self.initialize_mutable_binding(name, false);
let index = self.get_or_insert_binding(binding); 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 => { BindingOpcode::InitConst => {
let binding = self.initialize_immutable_binding(name); let binding = self.initialize_immutable_binding(name);
let index = self.get_or_insert_binding(binding); 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) { BindingOpcode::SetName => match self.set_mutable_binding(name) {
Ok(binding) => { Ok(binding) => {
let index = self.get_or_insert_binding(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) => { Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name); 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) => { Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop); 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]) { 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); self.emit_opcode(opcode);
for operand in operands { 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 { match operand {
Operand::Bool(v) => self.emit_u8(v.into()), Operand::Bool(v) => self.emit_u8(v.into()),
Operand::I8(v) => self.emit_i8(v), 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::U32(v) => self.emit_u32(v),
Operand::I64(v) => self.emit_i64(v), Operand::I64(v) => self.emit_i64(v),
Operand::U64(v) => self.emit_u64(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) { fn emit_push_literal(&mut self, literal: Literal) {
let index = self.get_or_insert_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) { fn emit_push_rational(&mut self, value: f64) {
@ -655,7 +700,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
Access::Variable { name } => { Access::Variable { name } => {
let binding = self.get_binding_value(name); let binding = self.get_binding_value(name);
let index = self.get_or_insert_binding(binding); 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 { Access::Property { access } => match access {
PropertyAccess::Simple(access) => match access.field() { 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()); let index = self.get_or_insert_name((*name).into());
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
@ -675,14 +720,14 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccess::Private(access) => { PropertyAccess::Private(access) => {
let index = self.get_or_insert_private_name(access.field()); let index = self.get_or_insert_private_name(access.field());
self.compile_expr(access.target(), true); 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() { PropertyAccess::Super(access) => match access.field() {
PropertyAccessField::Const(field) => { PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into()); let index = self.get_or_insert_name((*field).into());
self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::This); self.emit_opcode(Opcode::This);
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::Super);
@ -723,7 +768,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
let lex = self.current_environment.is_lex_binding(name); let lex = self.current_environment.is_lex_binding(name);
if !lex { if !lex {
self.emit(Opcode::GetLocator, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetLocator, index);
} }
expr_fn(self, 0); expr_fn(self, 0);
@ -735,11 +780,11 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
match self.set_mutable_binding(name) { match self.set_mutable_binding(name) {
Ok(binding) => { Ok(binding) => {
let index = self.get_or_insert_binding(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) => { Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name); 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) => { Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
@ -757,7 +802,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
expr_fn(self, 2); expr_fn(self, 2);
let index = self.get_or_insert_name((*name).into()); 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 { if !use_expr {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }
@ -777,7 +822,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
expr_fn(self, 1); expr_fn(self, 1);
let index = self.get_or_insert_private_name(access.field()); 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 { if !use_expr {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }
@ -788,7 +833,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.emit_opcode(Opcode::This); self.emit_opcode(Opcode::This);
expr_fn(self, 1); expr_fn(self, 1);
let index = self.get_or_insert_name((*name).into()); 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 { if !use_expr {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }
@ -816,7 +861,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
PropertyAccessField::Const(name) => { PropertyAccessField::Const(name) => {
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit(Opcode::DeletePropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::DeletePropertyByName, index);
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
@ -833,7 +878,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
Access::Variable { name } => { Access::Variable { name } => {
let binding = self.get_binding_value(name); let binding = self.get_binding_value(name);
let index = self.get_or_insert_binding(binding); 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 => { Access::This => {
self.emit_opcode(Opcode::PushTrue); self.emit_opcode(Opcode::PushTrue);
@ -895,7 +940,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
match access.field() { match access.field() {
PropertyAccessField::Const(field) => { PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into()); let index = self.get_or_insert_name((*field).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
} }
PropertyAccessField::Expr(field) => { PropertyAccessField::Expr(field) => {
self.compile_expr(field, true); self.compile_expr(field, true);
@ -907,7 +952,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.compile_expr(access.target(), true); self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
let index = self.get_or_insert_private_name(access.field()); 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) => { PropertyAccess::Super(access) => {
self.emit_opcode(Opcode::This); self.emit_opcode(Opcode::This);
@ -916,7 +961,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
match access.field() { match access.field() {
PropertyAccessField::Const(field) => { PropertyAccessField::Const(field) => {
let index = self.get_or_insert_name((*field).into()); let index = self.get_or_insert_name((*field).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.compile_expr(expr, true); self.compile_expr(expr, true);
@ -1002,7 +1047,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
match field { match field {
PropertyAccessField::Const(name) => { PropertyAccessField::Const(name) => {
let index = self.get_or_insert_name((*name).into()); let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetPropertyByName, index);
} }
PropertyAccessField::Expr(expr) => { PropertyAccessField::Expr(expr) => {
self.compile_expr(expr, true); self.compile_expr(expr, true);
@ -1015,7 +1060,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
OptionalOperationKind::PrivatePropertyAccess { field } => { OptionalOperationKind::PrivatePropertyAccess { field } => {
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
let index = self.get_or_insert_private_name(*field); 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::RotateLeft, &[Operand::U8(3)]);
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }
@ -1039,7 +1084,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
for arg in args { for arg in args {
self.compile_expr(arg, true); 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); self.emit_opcode(Opcode::PushUndefined);
@ -1148,16 +1193,16 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
if self.annex_b_function_names.contains(&name) { if self.annex_b_function_names.contains(&name) {
let binding = self.get_binding_value(name); let binding = self.get_binding_value(name);
let index = self.get_or_insert_binding(binding); 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) { match self.set_mutable_binding_var(name) {
Ok(binding) => { Ok(binding) => {
let index = self.get_or_insert_binding(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) => { Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(name); 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) => { Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
@ -1235,28 +1280,22 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
let index = self.function(function); let index = self.function(function);
if r#async && generator { if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator { } else if generator {
self.emit(Opcode::GetGenerator, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async && arrow { } else if r#async && arrow {
self.emit( self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]);
Opcode::GetAsyncArrowFunction,
&[Operand::U32(index), Operand::Bool(false)],
);
} else if r#async { } else if r#async {
self.emit( self.emit(
Opcode::GetFunctionAsync, Opcode::GetFunctionAsync,
&[Operand::U32(index), Operand::Bool(false)], &[Operand::Varying(index), Operand::Bool(false)],
); );
} else if arrow { } else if arrow {
self.emit( self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]);
Opcode::GetArrowFunction,
&[Operand::U32(index), Operand::Bool(false)],
);
} else { } else {
self.emit( self.emit(
Opcode::GetFunction, 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); self.functions.push(code);
if r#async && generator { if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator { } else if generator {
self.emit(Opcode::GetGenerator, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async && arrow { } else if r#async && arrow {
self.emit( self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]);
Opcode::GetAsyncArrowFunction,
&[Operand::U32(index), Operand::Bool(true)],
);
} else if r#async { } else if r#async {
self.emit( self.emit(
Opcode::GetFunctionAsync, Opcode::GetFunctionAsync,
&[Operand::U32(index), Operand::Bool(true)], &[Operand::Varying(index), Operand::Bool(true)],
); );
} else if arrow { } else if arrow {
self.emit( self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]);
Opcode::GetArrowFunction,
&[Operand::U32(index), Operand::Bool(true)],
);
} else { } else {
self.emit( self.emit(
Opcode::GetFunction, 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); self.functions.push(code);
if r#async && generator { if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator { } else if generator {
self.emit(Opcode::GetGenerator, &[Operand::U32(index)]); self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async && arrow { } else if r#async && arrow {
self.emit( self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]);
Opcode::GetAsyncArrowFunction,
&[Operand::U32(index), Operand::Bool(true)],
);
} else if r#async { } else if r#async {
self.emit( self.emit(
Opcode::GetFunctionAsync, Opcode::GetFunctionAsync,
&[Operand::U32(index), Operand::Bool(true)], &[Operand::Varying(index), Operand::Bool(true)],
); );
} else if arrow { } else if arrow {
self.emit( self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]);
Opcode::GetArrowFunction,
&[Operand::U32(index), Operand::Bool(true)],
);
} else { } else {
self.emit( self.emit(
Opcode::GetFunction, 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 { match kind {
CallKind::CallEval if contains_spread => self.emit_opcode(Opcode::CallEvalSpread), CallKind::CallEval if contains_spread => self.emit_opcode(Opcode::CallEvalSpread),
CallKind::CallEval => { 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 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 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 { 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 { if let Some(let_binding_indices) = let_binding_indices {
for index in &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); self.emit_opcode(Opcode::PopEnvironment);
iteration_env_labels = iteration_env_labels =
Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment)); Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment));
for index in let_binding_indices.iter().rev() { 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) { match self.set_mutable_binding(*ident) {
Ok(binding) => { Ok(binding) => {
let index = self.get_or_insert_binding(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) => { Err(BindingLocatorError::MutateImmutable) => {
let index = self.get_or_insert_name(*ident); 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) => { Err(BindingLocatorError::Silent) => {
self.emit_opcode(Opcode::Pop); 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!( let error_msg = self.get_or_insert_literal(Literal::String(js_string!(
"inner result was not an object" "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.patch_jump(skip_return);
self.emit_opcode(Opcode::IteratorPop); self.emit_opcode(Opcode::IteratorPop);

4
boa_engine/src/module/source.rs

@ -22,7 +22,7 @@ use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
use crate::{ use crate::{
builtins::{promise::PromiseCapability, Promise}, builtins::{promise::PromiseCapability, Promise},
bytecompiler::{ByteCompiler, FunctionSpec, Operand}, bytecompiler::{ByteCompiler, FunctionSpec},
environments::{BindingLocator, CompileTimeEnvironment, EnvironmentStack}, environments::{BindingLocator, CompileTimeEnvironment, EnvironmentStack},
module::ModuleKind, module::ModuleKind,
object::{FunctionObjectBuilder, JsPromise, RecursionLimiter}, object::{FunctionObjectBuilder, JsPromise, RecursionLimiter},
@ -1501,7 +1501,7 @@ impl SourceTextModule {
let binding = compiler.initialize_mutable_binding(name, false); let binding = compiler.initialize_mutable_binding(name, false);
let index = compiler.get_or_insert_binding(binding); let index = compiler.get_or_insert_binding(binding);
compiler.emit_opcode(Opcode::PushUndefined); 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. // 3. Append dn to declaredVarNames.
declared_var_names.push(name); 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; use thin_vec::ThinVec;
#[cfg(any(feature = "trace", feature = "flowgraph"))] #[cfg(any(feature = "trace", feature = "flowgraph"))]
use crate::vm::Opcode; use super::{Instruction, InstructionIterator};
#[cfg(any(feature = "trace", feature = "flowgraph"))] #[cfg(any(feature = "trace", feature = "flowgraph"))]
use boa_interner::{Interner, ToInternedString}; use boa_interner::{Interner, ToInternedString};
@ -299,10 +300,11 @@ impl CodeBlock {
/// ///
/// Returns an empty `String` if no operands are present. /// Returns an empty `String` if no operands are present.
#[cfg(any(feature = "trace", feature = "flowgraph"))] #[cfg(any(feature = "trace", feature = "flowgraph"))]
pub(crate) fn instruction_operands(&self, pc: &mut usize, interner: &Interner) -> String { pub(crate) fn instruction_operands(
use super::Instruction; &self,
instruction: &Instruction,
let instruction = Instruction::from_bytecode(&self.bytecode, pc); interner: &Interner,
) -> String {
match instruction { match instruction {
Instruction::SetFunctionName { prefix } => match prefix { Instruction::SetFunctionName { prefix } => match prefix {
0 => "prefix: none", 0 => "prefix: none",
@ -318,11 +320,11 @@ impl CodeBlock {
Instruction::PushInt8 { value } => value.to_string(), Instruction::PushInt8 { value } => value.to_string(),
Instruction::PushInt16 { value } => value.to_string(), Instruction::PushInt16 { value } => value.to_string(),
Instruction::PushInt32 { value } => value.to_string(), Instruction::PushInt32 { value } => value.to_string(),
Instruction::PushFloat { value } => ryu_js::Buffer::new().format(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::PushDouble { value } => ryu_js::Buffer::new().format(*value).to_string(),
Instruction::PushLiteral { index: value } Instruction::PushLiteral { index }
| Instruction::ThrowNewTypeError { message: value } | Instruction::ThrowNewTypeError { message: index } => index.value().to_string(),
| Instruction::Jump { address: value } Instruction::Jump { address: value }
| Instruction::JumpIfTrue { address: value } | Instruction::JumpIfTrue { address: value }
| Instruction::JumpIfFalse { address: value } | Instruction::JumpIfFalse { address: value }
| Instruction::JumpIfNotUndefined { address: value } | Instruction::JumpIfNotUndefined { address: value }
@ -331,8 +333,8 @@ impl CodeBlock {
| Instruction::Default { address: value } | Instruction::Default { address: value }
| Instruction::LogicalAnd { exit: value } | Instruction::LogicalAnd { exit: value }
| Instruction::LogicalOr { exit: value } | Instruction::LogicalOr { exit: value }
| Instruction::Coalesce { exit: value } | Instruction::Coalesce { exit: value } => value.to_string(),
| Instruction::CallEval { Instruction::CallEval {
argument_count: value, argument_count: value,
} }
| Instruction::Call { | Instruction::Call {
@ -344,7 +346,7 @@ impl CodeBlock {
| Instruction::SuperCall { | Instruction::SuperCall {
argument_count: value, argument_count: value,
} }
| Instruction::ConcatToString { value_count: value } => value.to_string(), | Instruction::ConcatToString { value_count: value } => value.value().to_string(),
Instruction::PushDeclarativeEnvironment { Instruction::PushDeclarativeEnvironment {
compile_environments_index, compile_environments_index,
} }
@ -354,8 +356,8 @@ impl CodeBlock {
Instruction::CopyDataProperties { Instruction::CopyDataProperties {
excluded_key_count: value1, excluded_key_count: value1,
excluded_key_count_computed: value2, excluded_key_count_computed: value2,
} } => format!("{}, {}", value1.value(), value2.value()),
| Instruction::GeneratorDelegateNext { Instruction::GeneratorDelegateNext {
return_method_undefined: value1, return_method_undefined: value1,
throw_method_undefined: value2, throw_method_undefined: value2,
} }
@ -365,29 +367,28 @@ impl CodeBlock {
} => { } => {
format!("{value1}, {value2}") format!("{value1}, {value2}")
} }
Instruction::TemplateLookup { exit: value, site } Instruction::TemplateLookup { exit: value, site } => format!("{value}, {site}"),
| Instruction::TemplateCreate { count: value, site } => { Instruction::TemplateCreate { count, site } => {
format!("{value}, {site}") format!("{}, {site}", count.value())
} }
Instruction::GetArrowFunction { index, method } Instruction::GetFunction { index, method }
| Instruction::GetAsyncArrowFunction { index, method }
| Instruction::GetFunction { index, method }
| Instruction::GetFunctionAsync { index, method } => { | Instruction::GetFunctionAsync { index, method } => {
let index = index.value() as usize;
format!( format!(
"{index:04}: '{}' (length: {}), method: {method}", "{index:04}: '{}' (length: {}), method: {method}",
self.functions[index as usize] self.functions[index].name().to_std_string_escaped(),
.name() self.functions[index].length
.to_std_string_escaped(),
self.functions[index as usize].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!( format!(
"{index:04}: '{}' (length: {})", "{index:04}: '{}' (length: {})",
self.functions[index as usize] self.functions[index].name().to_std_string_escaped(),
.name() self.functions[index].length
.to_std_string_escaped(),
self.functions[index as usize].length
) )
} }
Instruction::DefVar { index } Instruction::DefVar { index }
@ -400,12 +401,12 @@ impl CodeBlock {
| Instruction::SetName { index } | Instruction::SetName { index }
| Instruction::DeleteName { index } => { | Instruction::DeleteName { index } => {
format!( format!(
"{index:04}: '{}'", "{:04}: '{}'",
interner.resolve_expect(self.bindings[index as usize].name().sym()), index.value(),
interner.resolve_expect(self.bindings[index.value() as usize].name().sym()),
) )
} }
Instruction::GetPropertyByName { index } Instruction::GetPropertyByName { index }
| Instruction::GetMethod { index }
| Instruction::SetPropertyByName { index } | Instruction::SetPropertyByName { index }
| Instruction::DefineOwnPropertyByName { index } | Instruction::DefineOwnPropertyByName { index }
| Instruction::DefineClassStaticMethodByName { index } | Instruction::DefineClassStaticMethodByName { index }
@ -416,6 +417,8 @@ impl CodeBlock {
| Instruction::SetPropertySetterByName { index } | Instruction::SetPropertySetterByName { index }
| Instruction::DefineClassStaticSetterByName { index } | Instruction::DefineClassStaticSetterByName { index }
| Instruction::DefineClassSetterByName { index } | Instruction::DefineClassSetterByName { index }
| Instruction::InPrivate { index }
| Instruction::ThrowMutateImmutable { index }
| Instruction::DeletePropertyByName { index } | Instruction::DeletePropertyByName { index }
| Instruction::SetPrivateField { index } | Instruction::SetPrivateField { index }
| Instruction::DefinePrivateField { index } | Instruction::DefinePrivateField { index }
@ -426,12 +429,11 @@ impl CodeBlock {
| Instruction::PushClassFieldPrivate { index } | Instruction::PushClassFieldPrivate { index }
| Instruction::PushClassPrivateGetter { index } | Instruction::PushClassPrivateGetter { index }
| Instruction::PushClassPrivateSetter { index } | Instruction::PushClassPrivateSetter { index }
| Instruction::PushClassPrivateMethod { index } | Instruction::PushClassPrivateMethod { index } => {
| Instruction::InPrivate { index }
| Instruction::ThrowMutateImmutable { index } => {
format!( format!(
"{index:04}: '{}'", "{:04}: '{}'",
self.names[index as usize].to_std_string_escaped(), index.value(),
self.names[index.value() as usize].to_std_string_escaped(),
) )
} }
Instruction::PushPrivateEnvironment { name_indices } => { Instruction::PushPrivateEnvironment { name_indices } => {
@ -571,7 +573,10 @@ impl CodeBlock {
| Instruction::GetReturnValue | Instruction::GetReturnValue
| Instruction::SetReturnValue | Instruction::SetReturnValue
| Instruction::Nop => String::new(), | Instruction::Nop => String::new(),
Instruction::Reserved1
Instruction::U16Operands
| Instruction::U32Operands
| Instruction::Reserved1
| Instruction::Reserved2 | Instruction::Reserved2
| Instruction::Reserved3 | Instruction::Reserved3
| Instruction::Reserved4 | Instruction::Reserved4
@ -627,8 +632,7 @@ impl CodeBlock {
| Instruction::Reserved54 | Instruction::Reserved54
| Instruction::Reserved55 | Instruction::Reserved55
| Instruction::Reserved56 | Instruction::Reserved56
| Instruction::Reserved57 | Instruction::Reserved57 => unreachable!("Reserved opcodes are unrechable"),
| Instruction::Reserved58 => unreachable!("Reserved opcodes are unrechable"),
} }
} }
} }
@ -648,15 +652,14 @@ impl ToInternedString for CodeBlock {
format!("Compiled Output: '{}'", name.to_std_string_escaped()), format!("Compiled Output: '{}'", name.to_std_string_escaped()),
)); ));
let mut pc = 0; let mut iterator = InstructionIterator::new(&self.bytecode);
let mut count = 0;
while pc < self.bytecode.len() {
let instruction_start_pc = pc;
let opcode: Opcode = self.bytecode[instruction_start_pc].into(); let mut count = 0;
let opcode = opcode.as_str(); while let Some((instruction_start_pc, varying_operand_kind, instruction)) = iterator.next()
let previous_pc = pc; {
let operands = self.instruction_operands(&mut pc, interner); 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) 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() " 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!( 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; count += 1;
} }

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

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

22
boa_engine/src/vm/mod.rs

@ -32,11 +32,11 @@ mod runtime_limits;
#[cfg(feature = "flowgraph")] #[cfg(feature = "flowgraph")]
pub mod flowgraph; pub mod flowgraph;
pub(crate) use opcode::{Instruction, InstructionIterator, Opcode, VaryingOperandKind};
pub use runtime_limits::RuntimeLimits; pub use runtime_limits::RuntimeLimits;
pub use { pub use {
call_frame::{CallFrame, GeneratorResumeKind}, call_frame::{CallFrame, GeneratorResumeKind},
code_block::CodeBlock, code_block::CodeBlock,
opcode::{Instruction, InstructionIterator, Opcode},
}; };
pub(crate) use { pub(crate) use {
@ -246,13 +246,16 @@ impl Context<'_> {
} }
fn trace_execute_instruction(&mut self) -> JsResult<CompletionType> { fn trace_execute_instruction(&mut self) -> JsResult<CompletionType> {
let mut pc = self.vm.frame().pc as usize; let bytecodes = &self.vm.frame().code_block.bytecode;
let opcode: Opcode = self.vm.frame().code_block.read::<u8>(pc).into(); 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 let operands = self
.vm .vm
.frame() .frame()
.code_block .code_block
.instruction_operands(&mut pc, self.interner()); .instruction_operands(&instruction, self.interner());
let instant = Instant::now(); let instant = Instant::now();
let result = self.execute_instruction(); let result = self.execute_instruction();
@ -279,10 +282,17 @@ impl Context<'_> {
stack stack
}; };
let varying_operand_kind = match varying_operand_kind {
VaryingOperandKind::U8 => "",
VaryingOperandKind::U16 => ".U16",
VaryingOperandKind::U32 => ".U32",
};
println!( 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()), format!("{}μs", duration.as_micros()),
opcode.as_str(), instruction.opcode().as_str(),
varying_operand_kind,
TIME_COLUMN_WIDTH = Self::TIME_COLUMN_WIDTH, TIME_COLUMN_WIDTH = Self::TIME_COLUMN_WIDTH,
OPCODE_COLUMN_WIDTH = Self::OPCODE_COLUMN_WIDTH, OPCODE_COLUMN_WIDTH = Self::OPCODE_COLUMN_WIDTH,
OPERAND_COLUMN_WIDTH = Self::OPERAND_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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct InPrivate; pub(crate) struct InPrivate;
impl Operation for InPrivate { impl InPrivate {
const NAME: &'static str = "InPrivate"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - InPrivate"; let name = context.vm.frame().code_block.names[index].clone();
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();
let rhs = context.vm.pop(); let rhs = context.vm.pop();
let Some(rhs) = rhs.as_object() else { 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` /// `InstanceOf` implements the Opcode Operation for `Opcode::InstanceOf`
/// ///
/// Operation: /// Operation:

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

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

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

@ -10,13 +10,9 @@ use crate::{
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct ConcatToString; pub(crate) struct ConcatToString;
impl Operation for ConcatToString { impl ConcatToString {
const NAME: &'static str = "ConcatToString"; fn operation(context: &mut Context<'_>, value_count: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - ConcatToString"; let mut strings = Vec::with_capacity(value_count);
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u32>();
let mut strings = Vec::with_capacity(value_count as usize);
for _ in 0..value_count { for _ in 0..value_count {
strings.push(context.vm.pop().to_string(context)?); strings.push(context.vm.pop().to_string(context)?);
} }
@ -31,3 +27,23 @@ impl Operation for ConcatToString {
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct ThrowNewTypeError; pub(crate) struct ThrowNewTypeError;
impl Operation for ThrowNewTypeError { impl ThrowNewTypeError {
const NAME: &'static str = "ThrowNewTypeError"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - ThrowNewTypeError"; let msg = context.vm.frame().code_block.literals[index]
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let msg = context.vm.frame().code_block.literals[index as usize]
.as_string() .as_string()
.expect("throw message must be a string") .expect("throw message must be a string")
.clone(); .clone();
@ -133,3 +129,23 @@ impl Operation for ThrowNewTypeError {
Err(JsNativeError::typ().with_message(msg).into()) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct CopyDataProperties; pub(crate) struct CopyDataProperties;
impl Operation for CopyDataProperties { impl CopyDataProperties {
const NAME: &'static str = "CopyDataProperties"; fn operation(
const INSTRUCTION: &'static str = "INST - CopyDataProperties"; context: &mut Context<'_>,
excluded_key_count: usize,
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { excluded_key_count_computed: usize,
let excluded_key_count = context.vm.read::<u32>(); ) -> JsResult<CompletionType> {
let excluded_key_count_computed = context.vm.read::<u32>(); let mut excluded_keys = Vec::with_capacity(excluded_key_count);
let mut excluded_keys = Vec::with_capacity(excluded_key_count as usize);
for _ in 0..excluded_key_count { for _ in 0..excluded_key_count {
let key = context.vm.pop(); let key = context.vm.pop();
excluded_keys.push( excluded_keys.push(
@ -40,3 +39,26 @@ impl Operation for CopyDataProperties {
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct DefineClassStaticGetterByName; pub(crate) struct DefineClassStaticGetterByName;
impl Operation for DefineClassStaticGetterByName { impl DefineClassStaticGetterByName {
const NAME: &'static str = "DefineClassStaticGetterByName"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - DefineClassStaticGetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let function = context.vm.pop(); let function = context.vm.pop();
let class = context.vm.pop(); let class = context.vm.pop();
let class = class.as_object().expect("class must be object"); let class = class.as_object().expect("class must be object");
let key = context.vm.frame().code_block.names[index as usize] let key = context.vm.frame().code_block.names[index].clone().into();
.clone()
.into();
{ {
let function_object = function let function_object = function
.as_object() .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` /// `DefineClassGetterByName` implements the Opcode Operation for `Opcode::DefineClassGetterByName`
/// ///
/// Operation: /// Operation:
@ -63,18 +77,12 @@ impl Operation for DefineClassStaticGetterByName {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct DefineClassGetterByName; pub(crate) struct DefineClassGetterByName;
impl Operation for DefineClassGetterByName { impl DefineClassGetterByName {
const NAME: &'static str = "DefineClassGetterByName"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - DefineClassGetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let function = context.vm.pop(); let function = context.vm.pop();
let class_proto = context.vm.pop(); let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object"); let class_proto = class_proto.as_object().expect("class must be object");
let key = context.vm.frame().code_block.names[index as usize] let key = context.vm.frame().code_block.names[index].clone().into();
.clone()
.into();
{ {
let function_object = function let function_object = function
.as_object() .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` /// `DefineClassStaticGetterByValue` implements the Opcode Operation for `Opcode::DefineClassStaticGetterByValue`
/// ///
/// Operation: /// Operation:

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

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

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

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

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

@ -16,14 +16,11 @@ pub(crate) use own_property::*;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct DefVar; pub(crate) struct DefVar;
impl Operation for DefVar { impl DefVar {
const NAME: &'static str = "DefVar"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - DefVar"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// TODO: spec specifies to return `empty` on empty vars, but we're trying to initialize. // 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];
let binding_locator = context.vm.frame().code_block.bindings[index as usize];
if binding_locator.is_global() { if binding_locator.is_global() {
// already initialized at compile time // already initialized at compile time
@ -31,13 +28,33 @@ impl Operation for DefVar {
context.vm.environments.put_value_if_uninitialized( context.vm.environments.put_value_if_uninitialized(
binding_locator.environment_index(), binding_locator.environment_index(),
binding_locator.binding_index(), binding_locator.binding_index(),
JsValue::Undefined, JsValue::undefined(),
); );
} }
Ok(CompletionType::Normal) 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` /// `DefInitVar` implements the Opcode Operation for `Opcode::DefInitVar`
/// ///
/// Operation: /// Operation:
@ -45,14 +62,10 @@ impl Operation for DefVar {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct DefInitVar; pub(crate) struct DefInitVar;
impl Operation for DefInitVar { impl DefInitVar {
const NAME: &'static str = "DefInitVar"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - DefInitVar";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let value = context.vm.pop(); 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)?; 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` /// `PutLexicalValue` implements the Opcode Operation for `Opcode::PutLexicalValue`
/// ///
/// Operation: /// Operation:
@ -73,19 +106,37 @@ impl Operation for DefInitVar {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct PutLexicalValue; pub(crate) struct PutLexicalValue;
impl Operation for PutLexicalValue { impl PutLexicalValue {
const NAME: &'static str = "PutLexicalValue"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - PutLexicalValue"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let value = context.vm.pop(); 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( context.vm.environments.put_lexical_value(
binding_locator.environment_index(), binding_locator.environment_index(),
binding_locator.binding_index(), binding_locator.binding_index(),
value, value,
); );
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct DefineOwnPropertyByName; pub(crate) struct DefineOwnPropertyByName;
impl Operation for DefineOwnPropertyByName { impl DefineOwnPropertyByName {
const NAME: &'static str = "DefineOwnPropertyByName"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - DefineOwnPropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let value = context.vm.pop(); let value = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let object = if let Some(object) = object.as_object() { let object = if let Some(object) = object.as_object() {
@ -24,7 +20,7 @@ impl Operation for DefineOwnPropertyByName {
} else { } else {
object.to_object(context)? 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__( object.__define_own_property__(
&name.into(), &name.into(),
PropertyDescriptor::builder() 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` /// `DefineOwnPropertyByValue` implements the Opcode Operation for `Opcode::DefineOwnPropertyByValue`
/// ///
/// Operation: /// Operation:

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

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

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

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

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

@ -10,17 +10,33 @@ use crate::{
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetArrowFunction; 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 { impl Operation for GetArrowFunction {
const NAME: &'static str = "GetArrowFunction"; const NAME: &'static str = "GetArrowFunction";
const INSTRUCTION: &'static str = "INST - GetArrowFunction"; const INSTRUCTION: &'static str = "INST - GetArrowFunction";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u8>() as usize;
context.vm.read::<u8>(); Self::operation(context, index)
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); fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetAsyncArrowFunction; 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 { impl Operation for GetAsyncArrowFunction {
const NAME: &'static str = "GetAsyncArrowFunction"; const NAME: &'static str = "GetAsyncArrowFunction";
const INSTRUCTION: &'static str = "INST - GetAsyncArrowFunction"; const INSTRUCTION: &'static str = "INST - GetAsyncArrowFunction";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u8>() as usize;
context.vm.read::<u8>(); Self::operation(context, index)
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); fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetFunction; 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 { impl Operation for GetFunction {
const NAME: &'static str = "GetFunction"; const NAME: &'static str = "GetFunction";
const INSTRUCTION: &'static str = "INST - GetFunction"; const INSTRUCTION: &'static str = "INST - GetFunction";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u8>() as usize;
let method = context.vm.read::<u8>() != 0; let method = context.vm.read::<u8>() != 0;
let code = context.vm.frame().code_block.functions[index as usize].clone(); Self::operation(context, index, method)
let function = create_function_object_fast(code, false, false, method, context); }
context.vm.push(function);
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetFunctionAsync; 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 { impl Operation for GetFunctionAsync {
const NAME: &'static str = "GetFunctionAsync"; const NAME: &'static str = "GetFunctionAsync";
const INSTRUCTION: &'static str = "INST - GetFunctionAsync"; const INSTRUCTION: &'static str = "INST - GetFunctionAsync";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u8>() as usize;
let method = context.vm.read::<u8>() != 0; let method = context.vm.read::<u8>() != 0;
let code = context.vm.frame().code_block.functions[index as usize].clone(); Self::operation(context, index, method)
let function = create_function_object_fast(code, true, false, method, context); }
context.vm.push(function);
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetGenerator; 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 { impl Operation for GetGenerator {
const NAME: &'static str = "GetGenerator"; const NAME: &'static str = "GetGenerator";
const INSTRUCTION: &'static str = "INST - GetGenerator"; const INSTRUCTION: &'static str = "INST - GetGenerator";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u8>() as usize;
let code = context.vm.frame().code_block.functions[index as usize].clone(); Self::operation(context, index)
let function = create_generator_function_object(code, false, None, context); }
context.vm.push(function);
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetGeneratorAsync; 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 { impl Operation for GetGeneratorAsync {
const NAME: &'static str = "GetGeneratorAsync"; const NAME: &'static str = "GetGeneratorAsync";
const INSTRUCTION: &'static str = "INST - GetGeneratorAsync"; const INSTRUCTION: &'static str = "INST - GetGeneratorAsync";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u8>() as usize;
let code = context.vm.frame().code_block.functions[index as usize].clone(); Self::operation(context, index)
let function = create_generator_function_object(code, true, None, context); }
context.vm.push(function);
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetName; pub(crate) struct GetName;
impl Operation for GetName { impl GetName {
const NAME: &'static str = "GetName"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - GetName"; let mut binding_locator = context.vm.frame().code_block.bindings[index];
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)?; context.find_runtime_binding(&mut binding_locator)?;
let value = context.get_binding(binding_locator)?.ok_or_else(|| { let value = context.get_binding(binding_locator)?.ok_or_else(|| {
let name = context 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` /// `GetLocator` implements the Opcode Operation for `Opcode::GetLocator`
/// ///
/// Operation: /// Operation:
@ -39,18 +55,34 @@ impl Operation for GetName {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetLocator; 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 { impl Operation for GetLocator {
const NAME: &'static str = "GetLocator"; const NAME: &'static str = "GetLocator";
const INSTRUCTION: &'static str = "INST - GetLocator"; const INSTRUCTION: &'static str = "INST - GetLocator";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u8>();
let mut binding_locator = context.vm.frame().code_block.bindings[index as usize]; Self::operation(context, index as usize)
context.find_runtime_binding(&mut binding_locator)?; }
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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetNameAndLocator; pub(crate) struct GetNameAndLocator;
impl Operation for GetNameAndLocator { impl GetNameAndLocator {
const NAME: &'static str = "GetNameAndLocator"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - GetNameAndLocator"; let mut binding_locator = context.vm.frame().code_block.bindings[index];
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)?; context.find_runtime_binding(&mut binding_locator)?;
let value = context.get_binding(binding_locator)?.ok_or_else(|| { let value = context.get_binding(binding_locator)?.ok_or_else(|| {
let name = context 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` /// `GetNameOrUndefined` implements the Opcode Operation for `Opcode::GetNameOrUndefined`
/// ///
/// Operation: /// Operation:
@ -91,13 +139,9 @@ impl Operation for GetNameAndLocator {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetNameOrUndefined; pub(crate) struct GetNameOrUndefined;
impl Operation for GetNameOrUndefined { impl GetNameOrUndefined {
const NAME: &'static str = "GetNameOrUndefined"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - GetNameOrUndefined"; let mut binding_locator = context.vm.frame().code_block.bindings[index];
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];
let is_global = binding_locator.is_global(); let is_global = binding_locator.is_global();
@ -121,3 +165,23 @@ impl Operation for GetNameOrUndefined {
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetPrivateField; pub(crate) struct GetPrivateField;
impl Operation for GetPrivateField { impl GetPrivateField {
const NAME: &'static str = "GetPrivateField"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - GetPrivateField"; let name = context.vm.frame().code_block.names[index].clone();
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();
let value = context.vm.pop(); let value = context.vm.pop();
let base_obj = value.to_object(context)?; let base_obj = value.to_object(context)?;
@ -31,3 +27,23 @@ impl Operation for GetPrivateField {
Ok(CompletionType::Normal) 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::{ use crate::{
property::PropertyKey, property::PropertyKey,
vm::{opcode::Operation, CompletionType}, vm::{opcode::Operation, CompletionType},
Context, JsResult, JsValue, Context, JsResult,
}; };
/// `GetPropertyByName` implements the Opcode Operation for `Opcode::GetPropertyByName` /// `GetPropertyByName` implements the Opcode Operation for `Opcode::GetPropertyByName`
@ -11,13 +11,8 @@ use crate::{
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct GetPropertyByName; pub(crate) struct GetPropertyByName;
impl Operation for GetPropertyByName { impl GetPropertyByName {
const NAME: &'static str = "GetPropertyByName"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - GetPropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let receiver = context.vm.pop(); let receiver = context.vm.pop();
let value = context.vm.pop(); let value = context.vm.pop();
let object = if let Some(object) = value.as_object() { let object = if let Some(object) = value.as_object() {
@ -26,9 +21,7 @@ impl Operation for GetPropertyByName {
value.to_object(context)? value.to_object(context)?
}; };
let key = context.vm.frame().code_block.names[index as usize] let key = context.vm.frame().code_block.names[index].clone().into();
.clone()
.into();
let result = object.__get__(&key, receiver, context)?; let result = object.__get__(&key, receiver, context)?;
context.vm.push(result); 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` /// `GetPropertyByValue` implements the Opcode Operation for `Opcode::GetPropertyByValue`
/// ///
/// Operation: /// 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` /// `GetPropertyByValuePush` implements the Opcode Operation for `Opcode::GetPropertyByValuePush`
/// ///
/// Operation: /// Operation:

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

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

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

@ -33,4 +33,12 @@ impl Operation for Reserved {
fn execute(_: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(_: &mut Context<'_>) -> JsResult<CompletionType> {
unreachable!("Reserved opcodes are unreachable!") 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct PushClassFieldPrivate; pub(crate) struct PushClassFieldPrivate;
impl Operation for PushClassFieldPrivate { impl PushClassFieldPrivate {
const NAME: &'static str = "PushClassFieldPrivate"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - PushClassFieldPrivate"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
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();
let field_function_value = context.vm.pop(); let field_function_value = context.vm.pop();
let class_value = context.vm.pop(); let class_value = context.vm.pop();
@ -86,3 +83,23 @@ impl Operation for PushClassFieldPrivate {
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct PushClassPrivateMethod; pub(crate) struct PushClassPrivateMethod;
impl Operation for PushClassPrivateMethod { impl PushClassPrivateMethod {
const NAME: &'static str = "PushClassPrivateMethod"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - PushClassPrivateMethod"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
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();
let method = context.vm.pop(); let method = context.vm.pop();
let method_object = method.as_callable().expect("method must be callable"); 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` /// `PushClassPrivateGetter` implements the Opcode Operation for `Opcode::PushClassPrivateGetter`
/// ///
/// Operation: /// Operation:
@ -63,13 +80,10 @@ impl Operation for PushClassPrivateMethod {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct PushClassPrivateGetter; pub(crate) struct PushClassPrivateGetter;
impl Operation for PushClassPrivateGetter { impl PushClassPrivateGetter {
const NAME: &'static str = "PushClassPrivateGetter"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - PushClassPrivateGetter"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
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();
let getter = context.vm.pop(); let getter = context.vm.pop();
let getter_object = getter.as_callable().expect("getter must be callable"); let getter_object = getter.as_callable().expect("getter must be callable");
let class = context.vm.pop(); 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` /// `PushClassPrivateSetter` implements the Opcode Operation for `Opcode::PushClassPrivateSetter`
/// ///
/// Operation: /// Operation:
@ -102,13 +136,10 @@ impl Operation for PushClassPrivateGetter {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct PushClassPrivateSetter; pub(crate) struct PushClassPrivateSetter;
impl Operation for PushClassPrivateSetter { impl PushClassPrivateSetter {
const NAME: &'static str = "PushClassPrivateSetter"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - PushClassPrivateSetter"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
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();
let setter = context.vm.pop(); let setter = context.vm.pop();
let setter_object = setter.as_callable().expect("getter must be callable"); let setter_object = setter.as_callable().expect("getter must be callable");
let class = context.vm.pop(); let class = context.vm.pop();
@ -133,3 +164,23 @@ impl Operation for PushClassPrivateSetter {
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct PushLiteral; 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 { impl Operation for PushLiteral {
const NAME: &'static str = "PushLiteral"; const NAME: &'static str = "PushLiteral";
const INSTRUCTION: &'static str = "INST - PushLiteral"; const INSTRUCTION: &'static str = "INST - PushLiteral";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize; let index = context.vm.read::<u8>();
let value = context.vm.frame().code_block.literals[index].clone(); Self::operation(context, index as usize)
context.vm.push(value); }
Ok(CompletionType::Normal)
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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct ThrowMutateImmutable; pub(crate) struct ThrowMutateImmutable;
impl Operation for ThrowMutateImmutable { impl ThrowMutateImmutable {
const NAME: &'static str = "ThrowMutateImmutable"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - ThrowMutateImmutable"; let name = &context.vm.frame().code_block.names[index];
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let name = &context.vm.frame().code_block.names[index as usize];
Err(JsNativeError::typ() Err(JsNativeError::typ()
.with_message(format!( .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` /// `SetName` implements the Opcode Operation for `Opcode::SetName`
/// ///
/// Operation: /// Operation:
@ -35,13 +51,9 @@ impl Operation for ThrowMutateImmutable {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct SetName; pub(crate) struct SetName;
impl Operation for SetName { impl SetName {
const NAME: &'static str = "SetName"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - SetName"; let mut binding_locator = context.vm.frame().code_block.bindings[index];
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];
let value = context.vm.pop(); let value = context.vm.pop();
context.find_runtime_binding(&mut binding_locator)?; 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` /// `SetNameByLocator` implements the Opcode Operation for `Opcode::SetNameByLocator`
/// ///
/// Operation: /// Operation:

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

@ -14,13 +14,9 @@ use crate::{
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct SetPrivateField; pub(crate) struct SetPrivateField;
impl Operation for SetPrivateField { impl SetPrivateField {
const NAME: &'static str = "SetPrivateField"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - SetPrivateField"; let name = context.vm.frame().code_block.names[index].clone();
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();
let value = context.vm.pop(); let value = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let base_obj = object.to_object(context)?; 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` /// `DefinePrivateField` implements the Opcode Operation for `Opcode::DefinePrivateField`
/// ///
/// Operation: /// Operation:
@ -44,13 +60,10 @@ impl Operation for SetPrivateField {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct DefinePrivateField; pub(crate) struct DefinePrivateField;
impl Operation for DefinePrivateField { impl DefinePrivateField {
const NAME: &'static str = "DefinePrivateField"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - DefinePrivateField"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
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();
let value = context.vm.pop(); let value = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let object = object 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` /// `SetPrivateMethod` implements the Opcode Operation for `Opcode::SetPrivateMethod`
/// ///
/// Operation: /// Operation:
@ -72,13 +105,10 @@ impl Operation for DefinePrivateField {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct SetPrivateMethod; pub(crate) struct SetPrivateMethod;
impl Operation for SetPrivateMethod { impl SetPrivateMethod {
const NAME: &'static str = "SetPrivateMethod"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - SetPrivateMethod"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
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();
let value = context.vm.pop(); let value = context.vm.pop();
let value = value.as_callable().expect("method must be callable"); 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` /// `SetPrivateSetter` implements the Opcode Operation for `Opcode::SetPrivateSetter`
/// ///
/// Operation: /// Operation:
@ -119,13 +169,10 @@ impl Operation for SetPrivateMethod {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct SetPrivateSetter; pub(crate) struct SetPrivateSetter;
impl Operation for SetPrivateSetter { impl SetPrivateSetter {
const NAME: &'static str = "SetPrivateSetter"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - SetPrivateSetter"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
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();
let value = context.vm.pop(); let value = context.vm.pop();
let value = value.as_callable().expect("setter must be callable"); let value = value.as_callable().expect("setter must be callable");
let object = context.vm.pop(); 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` /// `SetPrivateGetter` implements the Opcode Operation for `Opcode::SetPrivateGetter`
/// ///
/// Operation: /// Operation:
@ -157,13 +224,10 @@ impl Operation for SetPrivateSetter {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct SetPrivateGetter; pub(crate) struct SetPrivateGetter;
impl Operation for SetPrivateGetter { impl SetPrivateGetter {
const NAME: &'static str = "SetPrivateGetter"; #[allow(clippy::unnecessary_wraps)]
const INSTRUCTION: &'static str = "INST - SetPrivateGetter"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = context.vm.frame().code_block.names[index].clone();
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();
let value = context.vm.pop(); let value = context.vm.pop();
let value = value.as_callable().expect("getter must be callable"); let value = value.as_callable().expect("getter must be callable");
let object = context.vm.pop(); let object = context.vm.pop();
@ -187,3 +251,23 @@ impl Operation for SetPrivateGetter {
Ok(CompletionType::Normal) 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)] #[derive(Debug, Clone, Copy)]
pub(crate) struct SetPropertyByName; pub(crate) struct SetPropertyByName;
impl Operation for SetPropertyByName { impl SetPropertyByName {
const NAME: &'static str = "SetPropertyByName"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - SetPropertyByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let value = context.vm.pop(); let value = context.vm.pop();
let receiver = context.vm.pop(); let receiver = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
@ -30,9 +25,7 @@ impl Operation for SetPropertyByName {
object.to_object(context)? object.to_object(context)?
}; };
let name: PropertyKey = context.vm.frame().code_block.names[index as usize] let name: PropertyKey = context.vm.frame().code_block.names[index].clone().into();
.clone()
.into();
let succeeded = object.__set__(name.clone(), value.clone(), receiver, context)?; let succeeded = object.__set__(name.clone(), value.clone(), receiver, context)?;
if !succeeded && context.vm.frame().code_block.strict() { 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` /// `SetPropertyByValue` implements the Opcode Operation for `Opcode::SetPropertyByValue`
/// ///
/// Operation: /// Operation:
@ -156,18 +169,12 @@ impl Operation for SetPropertyByValue {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct SetPropertyGetterByName; pub(crate) struct SetPropertyGetterByName;
impl Operation for SetPropertyGetterByName { impl SetPropertyGetterByName {
const NAME: &'static str = "SetPropertyGetterByName"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - SetPropertyGetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let value = context.vm.pop(); let value = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let object = object.to_object(context)?; let object = object.to_object(context)?;
let name = context.vm.frame().code_block.names[index as usize] let name = context.vm.frame().code_block.names[index].clone().into();
.clone()
.into();
let set = object let set = object
.__get_own_property__(&name, context)? .__get_own_property__(&name, context)?
.as_ref() .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` /// `SetPropertyGetterByValue` implements the Opcode Operation for `Opcode::SetPropertyGetterByValue`
/// ///
/// Operation: /// Operation:
@ -230,18 +257,12 @@ impl Operation for SetPropertyGetterByValue {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct SetPropertySetterByName; pub(crate) struct SetPropertySetterByName;
impl Operation for SetPropertySetterByName { impl SetPropertySetterByName {
const NAME: &'static str = "SetPropertySetterByName"; fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
const INSTRUCTION: &'static str = "INST - SetPropertySetterByName";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>();
let value = context.vm.pop(); let value = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let object = object.to_object(context)?; let object = object.to_object(context)?;
let name = context.vm.frame().code_block.names[index as usize] let name = context.vm.frame().code_block.names[index].clone().into();
.clone()
.into();
let get = object let get = object
.__get_own_property__(&name, context)? .__get_own_property__(&name, context)?
.as_ref() .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` /// `SetPropertySetterByValue` implements the Opcode Operation for `Opcode::SetPropertySetterByValue`
/// ///
/// Operation: /// Operation:

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

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