From 332fd658a84d3c786b9c43e936f8d3e441d5cc07 Mon Sep 17 00:00:00 2001 From: Haled Odat <8566042+HalidOdat@users.noreply.github.com> Date: Sat, 30 Sep 2023 13:56:38 +0200 Subject: [PATCH] Varying length instruction operands (#3253) * Implement varying length operands * Apply review * Apply review --- boa_engine/src/bytecompiler/class.rs | 98 +++--- .../declaration/declaration_pattern.rs | 24 +- boa_engine/src/bytecompiler/declarations.rs | 26 +- .../src/bytecompiler/expression/assign.rs | 20 +- .../src/bytecompiler/expression/binary.rs | 7 +- boa_engine/src/bytecompiler/expression/mod.rs | 23 +- .../bytecompiler/expression/object_literal.rs | 18 +- .../src/bytecompiler/expression/unary.rs | 4 +- .../src/bytecompiler/expression/update.rs | 20 +- boa_engine/src/bytecompiler/mod.rs | 173 ++++++---- boa_engine/src/bytecompiler/statement/loop.rs | 8 +- boa_engine/src/bytecompiler/utils.rs | 2 +- boa_engine/src/module/source.rs | 4 +- boa_engine/src/vm/code_block.rs | 109 +++--- boa_engine/src/vm/flowgraph/mod.rs | 27 +- boa_engine/src/vm/mod.rs | 22 +- boa_engine/src/vm/opcode/binary_ops/mod.rs | 30 +- boa_engine/src/vm/opcode/call/mod.rs | 60 +++- boa_engine/src/vm/opcode/concat/mod.rs | 30 +- .../src/vm/opcode/control_flow/throw.rs | 30 +- boa_engine/src/vm/opcode/copy/mod.rs | 38 +- .../src/vm/opcode/define/class/getter.rs | 64 +++- .../src/vm/opcode/define/class/method.rs | 64 +++- .../src/vm/opcode/define/class/setter.rs | 64 +++- boa_engine/src/vm/opcode/define/mod.rs | 95 +++-- .../src/vm/opcode/define/own_property.rs | 30 +- boa_engine/src/vm/opcode/delete/mod.rs | 62 +++- boa_engine/src/vm/opcode/environment/mod.rs | 30 +- boa_engine/src/vm/opcode/get/function.rs | 122 +++++-- boa_engine/src/vm/opcode/get/generator.rs | 54 ++- boa_engine/src/vm/opcode/get/name.rs | 116 +++++-- boa_engine/src/vm/opcode/get/private.rs | 30 +- boa_engine/src/vm/opcode/get/property.rs | 60 ++-- boa_engine/src/vm/opcode/mod.rs | 325 ++++++++++++------ boa_engine/src/vm/opcode/modifier.rs | 39 +++ boa_engine/src/vm/opcode/new/mod.rs | 30 +- boa_engine/src/vm/opcode/nop/mod.rs | 8 + boa_engine/src/vm/opcode/push/class/field.rs | 31 +- .../src/vm/opcode/push/class/private.rs | 93 +++-- boa_engine/src/vm/opcode/push/literal.rs | 25 +- boa_engine/src/vm/opcode/set/name.rs | 60 +++- boa_engine/src/vm/opcode/set/private.rs | 154 +++++++-- boa_engine/src/vm/opcode/set/property.rs | 97 ++++-- boa_engine/src/vm/opcode/templates/mod.rs | 34 +- 44 files changed, 1732 insertions(+), 728 deletions(-) create mode 100644 boa_engine/src/vm/opcode/modifier.rs diff --git a/boa_engine/src/bytecompiler/class.rs b/boa_engine/src/bytecompiler/class.rs index e4bb14803cd..98db47e5736 100644 --- a/boa_engine/src/bytecompiler/class.rs +++ b/boa_engine/src/bytecompiler/class.rs @@ -80,7 +80,7 @@ impl ByteCompiler<'_, '_> { self.functions.push(code); self.emit( Opcode::GetFunction, - &[Operand::U32(index), Operand::Bool(false)], + &[Operand::Varying(index), Operand::Bool(false)], ); let class_env: Option = match class.name() { @@ -129,9 +129,9 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit( + self.emit_with_varying_operand( Opcode::DefineClassStaticGetterByName, - &[Operand::U32(index)], + index, ); } PropertyName::Computed(name_node) => { @@ -145,9 +145,9 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit( + self.emit_with_varying_operand( Opcode::DefineClassStaticSetterByName, - &[Operand::U32(index)], + index, ); } PropertyName::Computed(name_node) => { @@ -161,9 +161,9 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit( + self.emit_with_varying_operand( Opcode::DefineClassStaticMethodByName, - &[Operand::U32(index)], + index, ); } PropertyName::Computed(name_node) => { @@ -177,9 +177,9 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit( + self.emit_with_varying_operand( Opcode::DefineClassStaticMethodByName, - &[Operand::U32(index)], + index, ); } PropertyName::Computed(name_node) => { @@ -193,9 +193,9 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit( + self.emit_with_varying_operand( Opcode::DefineClassStaticMethodByName, - &[Operand::U32(index)], + index, ); } PropertyName::Computed(name_node) => { @@ -209,9 +209,9 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit( + self.emit_with_varying_operand( Opcode::DefineClassStaticMethodByName, - &[Operand::U32(index)], + index, ); } PropertyName::Computed(name_node) => { @@ -230,32 +230,32 @@ impl ByteCompiler<'_, '_> { MethodDefinition::Get(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::SetPrivateGetter, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPrivateGetter, index); } MethodDefinition::Set(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::SetPrivateSetter, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPrivateSetter, index); } MethodDefinition::Ordinary(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::SetPrivateMethod, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPrivateMethod, index); } MethodDefinition::Async(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::SetPrivateMethod, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPrivateMethod, index); } MethodDefinition::Generator(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::SetPrivateMethod, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPrivateMethod, index); } MethodDefinition::AsyncGenerator(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::SetPrivateMethod, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPrivateMethod, index); } } } @@ -299,7 +299,7 @@ impl ByteCompiler<'_, '_> { self.functions.push(code); self.emit( Opcode::GetFunction, - &[Operand::U32(index), Operand::Bool(false)], + &[Operand::Varying(index), Operand::Bool(false)], ); self.emit_opcode(Opcode::PushClassField); } @@ -334,9 +334,9 @@ impl ByteCompiler<'_, '_> { self.functions.push(code); self.emit( Opcode::GetFunction, - &[Operand::U32(index), Operand::Bool(false)], + &[Operand::Varying(index), Operand::Bool(false)], ); - self.emit(Opcode::PushClassFieldPrivate, &[Operand::U32(name_index)]); + self.emit_with_varying_operand(Opcode::PushClassFieldPrivate, name_index); } ClassElement::StaticFieldDefinition(name, field) => { self.emit_opcode(Opcode::Dup); @@ -379,12 +379,12 @@ impl ByteCompiler<'_, '_> { self.functions.push(code); self.emit( Opcode::GetFunction, - &[Operand::U32(index), Operand::Bool(false)], + &[Operand::Varying(index), Operand::Bool(false)], ); self.emit_opcode(Opcode::SetHomeObjectClass); - self.emit(Opcode::Call, &[Operand::U32(0)]); + self.emit_with_varying_operand(Opcode::Call, 0); if let Some(name_index) = name_index { - self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(name_index)]); + self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, name_index); } else { self.emit_opcode(Opcode::DefineOwnPropertyByValue); } @@ -397,7 +397,7 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::PushUndefined); } let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::DefinePrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefinePrivateField, index); } ClassElement::StaticBlock(body) => { self.emit_opcode(Opcode::Dup); @@ -429,10 +429,10 @@ impl ByteCompiler<'_, '_> { self.functions.push(code); self.emit( Opcode::GetFunction, - &[Operand::U32(index), Operand::Bool(false)], + &[Operand::Varying(index), Operand::Bool(false)], ); self.emit_opcode(Opcode::SetHomeObjectClass); - self.emit(Opcode::Call, &[Operand::U32(0)]); + self.emit_with_varying_operand(Opcode::Call, 0); self.emit_opcode(Opcode::Pop); } // TODO: set names for private methods @@ -442,32 +442,32 @@ impl ByteCompiler<'_, '_> { MethodDefinition::Get(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::PushClassPrivateGetter, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::PushClassPrivateGetter, index); } MethodDefinition::Set(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::PushClassPrivateSetter, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::PushClassPrivateSetter, index); } MethodDefinition::Ordinary(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::PushClassPrivateMethod, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index); } MethodDefinition::Async(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::PushClassPrivateMethod, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index); } MethodDefinition::Generator(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::PushClassPrivateMethod, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index); } MethodDefinition::AsyncGenerator(expr) => { self.method(expr.into(), class_name); let index = self.get_or_insert_private_name(*name); - self.emit(Opcode::PushClassPrivateMethod, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index); } } } @@ -487,7 +487,10 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineClassGetterByName, &[Operand::U32(index)]); + self.emit_with_varying_operand( + Opcode::DefineClassGetterByName, + index, + ); } PropertyName::Computed(name_node) => { self.compile_expr(name_node, true); @@ -500,7 +503,10 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineClassSetterByName, &[Operand::U32(index)]); + self.emit_with_varying_operand( + Opcode::DefineClassSetterByName, + index, + ); } PropertyName::Computed(name_node) => { self.compile_expr(name_node, true); @@ -513,7 +519,10 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineClassMethodByName, &[Operand::U32(index)]); + self.emit_with_varying_operand( + Opcode::DefineClassMethodByName, + index, + ); } PropertyName::Computed(name_node) => { self.compile_expr(name_node, true); @@ -526,7 +535,10 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineClassMethodByName, &[Operand::U32(index)]); + self.emit_with_varying_operand( + Opcode::DefineClassMethodByName, + index, + ); } PropertyName::Computed(name_node) => { self.compile_expr(name_node, true); @@ -539,7 +551,10 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineClassMethodByName, &[Operand::U32(index)]); + self.emit_with_varying_operand( + Opcode::DefineClassMethodByName, + index, + ); } PropertyName::Computed(name_node) => { self.compile_expr(name_node, true); @@ -552,7 +567,10 @@ impl ByteCompiler<'_, '_> { PropertyName::Literal(name) => { self.method(expr.into(), class_name); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineClassMethodByName, &[Operand::U32(index)]); + self.emit_with_varying_operand( + Opcode::DefineClassMethodByName, + index, + ); } PropertyName::Computed(name_node) => { self.compile_expr(name_node, true); diff --git a/boa_engine/src/bytecompiler/declaration/declaration_pattern.rs b/boa_engine/src/bytecompiler/declaration/declaration_pattern.rs index 37bee0444ae..946be8bae37 100644 --- a/boa_engine/src/bytecompiler/declaration/declaration_pattern.rs +++ b/boa_engine/src/bytecompiler/declaration/declaration_pattern.rs @@ -40,7 +40,10 @@ impl ByteCompiler<'_, '_> { match name { PropertyName::Literal(name) => { let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand( + Opcode::GetPropertyByName, + index, + ); } PropertyName::Computed(node) => { self.compile_expr(node, true); @@ -81,8 +84,8 @@ impl ByteCompiler<'_, '_> { self.emit( Opcode::CopyDataProperties, &[ - Operand::U32(excluded_keys.len() as u32), - Operand::U32(additional_excluded_keys_count), + Operand::Varying(excluded_keys.len() as u32), + Operand::Varying(additional_excluded_keys_count), ], ); self.emit_binding(def, *ident); @@ -100,7 +103,10 @@ impl ByteCompiler<'_, '_> { } self.emit( Opcode::CopyDataProperties, - &[Operand::U32(excluded_keys.len() as u32), Operand::U32(0)], + &[ + Operand::Varying(excluded_keys.len() as u32), + Operand::Varying(0), + ], ); self.access_set( Access::Property { access }, @@ -118,7 +124,10 @@ impl ByteCompiler<'_, '_> { match name { PropertyName::Literal(name) => { let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand( + Opcode::GetPropertyByName, + index, + ); } PropertyName::Computed(node) => { self.compile_expr(node, true); @@ -158,7 +167,10 @@ impl ByteCompiler<'_, '_> { match name { PropertyName::Literal(name) => { let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand( + Opcode::GetPropertyByName, + index, + ); } PropertyName::Computed(node) => { self.compile_expr(node, true); diff --git a/boa_engine/src/bytecompiler/declarations.rs b/boa_engine/src/bytecompiler/declarations.rs index 60cdc66169b..27d94fc1cca 100644 --- a/boa_engine/src/bytecompiler/declarations.rs +++ b/boa_engine/src/bytecompiler/declarations.rs @@ -572,7 +572,7 @@ impl ByteCompiler<'_, '_> { let binding = self.initialize_mutable_binding(f, true); let index = self.get_or_insert_binding(binding); self.emit_opcode(Opcode::PushUndefined); - self.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefInitVar, index); } } @@ -719,18 +719,18 @@ impl ByteCompiler<'_, '_> { let index = self.functions.len() as u32; self.functions.push(code); if r#async && generator { - self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); } else if generator { - self.emit(Opcode::GetGenerator, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetGenerator, index); } else if r#async { self.emit( Opcode::GetFunctionAsync, - &[Operand::U32(index), Operand::Bool(false)], + &[Operand::Varying(index), Operand::Bool(false)], ); } else { self.emit( Opcode::GetFunction, - &[Operand::U32(index), Operand::Bool(false)], + &[Operand::Varying(index), Operand::Bool(false)], ); } @@ -744,11 +744,11 @@ impl ByteCompiler<'_, '_> { match self.set_mutable_binding(name) { Ok(binding) => { let index = self.get_or_insert_binding(binding); - self.emit(Opcode::SetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetName, index); } Err(BindingLocatorError::MutateImmutable) => { let index = self.get_or_insert_name(name); - self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index); } Err(BindingLocatorError::Silent) => { self.emit_opcode(Opcode::Pop); @@ -761,7 +761,7 @@ impl ByteCompiler<'_, '_> { self.create_mutable_binding(name, !strict); let binding = self.initialize_mutable_binding(name, !strict); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefInitVar, index); } } } @@ -787,7 +787,7 @@ impl ByteCompiler<'_, '_> { let binding = self.initialize_mutable_binding(name, !strict); let index = self.get_or_insert_binding(binding); self.emit_opcode(Opcode::PushUndefined); - self.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefInitVar, index); } } } @@ -1056,14 +1056,14 @@ impl ByteCompiler<'_, '_> { // a. Let initialValue be ! env.GetBindingValue(n, false). let binding = self.get_binding_value(n); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::GetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetName, index); } // 5. Perform ! varEnv.InitializeBinding(n, initialValue). let binding = self.initialize_mutable_binding(n, true); let index = self.get_or_insert_binding(binding); self.emit_opcode(Opcode::PushUndefined); - self.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefInitVar, index); // 6. NOTE: A var with the same name as a formal parameter initially has // the same value as the corresponding initialized parameter. @@ -1090,7 +1090,7 @@ impl ByteCompiler<'_, '_> { let binding = self.initialize_mutable_binding(n, true); let index = self.get_or_insert_binding(binding); self.emit_opcode(Opcode::PushUndefined); - self.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefInitVar, index); } } @@ -1122,7 +1122,7 @@ impl ByteCompiler<'_, '_> { let binding = self.initialize_mutable_binding(f, true); let index = self.get_or_insert_binding(binding); self.emit_opcode(Opcode::PushUndefined); - self.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefInitVar, index); // c. Append F to instantiatedVarNames. instantiated_var_names.push(f); diff --git a/boa_engine/src/bytecompiler/expression/assign.rs b/boa_engine/src/bytecompiler/expression/assign.rs index 8fb8f932a73..9efc49e2b23 100644 --- a/boa_engine/src/bytecompiler/expression/assign.rs +++ b/boa_engine/src/bytecompiler/expression/assign.rs @@ -60,9 +60,9 @@ impl ByteCompiler<'_, '_> { let lex = self.current_environment.is_lex_binding(name); if lex { - self.emit(Opcode::GetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetName, index); } else { - self.emit(Opcode::GetNameAndLocator, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetNameAndLocator, index); } if short_circuit { @@ -79,11 +79,11 @@ impl ByteCompiler<'_, '_> { match self.set_mutable_binding(name) { Ok(binding) => { let index = self.get_or_insert_binding(binding); - self.emit(Opcode::SetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetName, index); } Err(BindingLocatorError::MutateImmutable) => { let index = self.get_or_insert_name(name); - self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index); } Err(BindingLocatorError::Silent) => { self.emit_opcode(Opcode::Pop); @@ -102,7 +102,7 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); if short_circuit { pop_count = 2; early_exit = Some(self.emit_opcode_with_operand(opcode)); @@ -112,7 +112,7 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(opcode); } - self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPropertyByName, index); if !use_expr { self.emit_opcode(Opcode::Pop); } @@ -145,7 +145,7 @@ impl ByteCompiler<'_, '_> { self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); - self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPrivateField, index); if short_circuit { pop_count = 1; early_exit = Some(self.emit_opcode_with_operand(opcode)); @@ -155,7 +155,7 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(opcode); } - self.emit(Opcode::SetPrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPrivateField, index); if !use_expr { self.emit_opcode(Opcode::Pop); } @@ -169,7 +169,7 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::Swap); self.emit_opcode(Opcode::This); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); if short_circuit { pop_count = 2; early_exit = Some(self.emit_opcode_with_operand(opcode)); @@ -179,7 +179,7 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(opcode); } - self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPropertyByName, index); if !use_expr { self.emit_opcode(Opcode::Pop); } diff --git a/boa_engine/src/bytecompiler/expression/binary.rs b/boa_engine/src/bytecompiler/expression/binary.rs index c29e23c586c..97ec9daf6ef 100644 --- a/boa_engine/src/bytecompiler/expression/binary.rs +++ b/boa_engine/src/bytecompiler/expression/binary.rs @@ -3,10 +3,7 @@ use boa_ast::expression::operator::{ Binary, BinaryInPrivate, }; -use crate::{ - bytecompiler::{ByteCompiler, Operand}, - vm::Opcode, -}; +use crate::{bytecompiler::ByteCompiler, vm::Opcode}; impl ByteCompiler<'_, '_> { pub(crate) fn compile_binary(&mut self, binary: &Binary, use_expr: bool) { @@ -100,7 +97,7 @@ impl ByteCompiler<'_, '_> { pub(crate) fn compile_binary_in_private(&mut self, binary: &BinaryInPrivate, use_expr: bool) { let index = self.get_or_insert_private_name(*binary.lhs()); self.compile_expr(binary.rhs(), true); - self.emit(Opcode::InPrivate, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::InPrivate, index); if !use_expr { self.emit_opcode(Opcode::Pop); diff --git a/boa_engine/src/bytecompiler/expression/mod.rs b/boa_engine/src/bytecompiler/expression/mod.rs index 7dfc94b29c3..6755e992048 100644 --- a/boa_engine/src/bytecompiler/expression/mod.rs +++ b/boa_engine/src/bytecompiler/expression/mod.rs @@ -66,9 +66,9 @@ impl ByteCompiler<'_, '_> { } } - self.emit( + self.emit_with_varying_operand( Opcode::ConcatToString, - &[Operand::U32(template_literal.elements().len() as u32)], + template_literal.elements().len() as u32, ); if !use_expr { @@ -228,7 +228,7 @@ impl ByteCompiler<'_, '_> { match access.field() { PropertyAccessField::Const(field) => { let index = self.get_or_insert_name((*field).into()); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); } PropertyAccessField::Expr(field) => { self.compile_expr(field, true); @@ -240,7 +240,7 @@ impl ByteCompiler<'_, '_> { self.compile_expr(access.target(), true); self.emit(Opcode::Dup, &[]); let index = self.get_or_insert_private_name(access.field()); - self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPrivateField, index); } expr => { self.emit_opcode(Opcode::PushUndefined); @@ -267,8 +267,10 @@ impl ByteCompiler<'_, '_> { )); } - self.emit(Opcode::TemplateCreate, &[Operand::U32(count)]); - self.emit_u64(site); + self.emit( + Opcode::TemplateCreate, + &[Operand::Varying(count), Operand::U64(site)], + ); self.patch_jump(jump_label); @@ -276,10 +278,7 @@ impl ByteCompiler<'_, '_> { self.compile_expr(expr, true); } - self.emit( - Opcode::Call, - &[Operand::U32(template.exprs().len() as u32 + 1)], - ); + self.emit_with_varying_operand(Opcode::Call, template.exprs().len() as u32 + 1); } Expression::Class(class) => self.class(class, true), Expression::SuperCall(super_call) => { @@ -310,9 +309,9 @@ impl ByteCompiler<'_, '_> { if contains_spread { self.emit_opcode(Opcode::SuperCallSpread); } else { - self.emit( + self.emit_with_varying_operand( Opcode::SuperCall, - &[Operand::U32(super_call.arguments().len() as u32)], + super_call.arguments().len() as u32, ); } diff --git a/boa_engine/src/bytecompiler/expression/object_literal.rs b/boa_engine/src/bytecompiler/expression/object_literal.rs index 5dcf6ed55ca..10dea9d1665 100644 --- a/boa_engine/src/bytecompiler/expression/object_literal.rs +++ b/boa_engine/src/bytecompiler/expression/object_literal.rs @@ -18,7 +18,7 @@ impl ByteCompiler<'_, '_> { PropertyDefinition::IdentifierReference(ident) => { let index = self.get_or_insert_name(*ident); self.access_get(Access::Variable { name: *ident }, true); - self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); } PropertyDefinition::Property(name, expr) => match name { PropertyName::Literal(name) => { @@ -27,7 +27,7 @@ impl ByteCompiler<'_, '_> { if *name == Sym::__PROTO__ && !self.json_parse { self.emit_opcode(Opcode::SetPrototype); } else { - self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); } } PropertyName::Computed(name_node) => { @@ -49,7 +49,7 @@ impl ByteCompiler<'_, '_> { self.object_method(expr.into()); self.emit_opcode(Opcode::SetHomeObject); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::SetPropertyGetterByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPropertyGetterByName, index); } PropertyName::Computed(name_node) => { self.compile_object_literal_computed_method( @@ -64,7 +64,7 @@ impl ByteCompiler<'_, '_> { self.object_method(expr.into()); self.emit_opcode(Opcode::SetHomeObject); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::SetPropertySetterByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPropertySetterByName, index); } PropertyName::Computed(name_node) => { self.compile_object_literal_computed_method( @@ -79,7 +79,7 @@ impl ByteCompiler<'_, '_> { self.object_method(expr.into()); self.emit_opcode(Opcode::SetHomeObject); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); } PropertyName::Computed(name_node) => { self.compile_object_literal_computed_method( @@ -94,7 +94,7 @@ impl ByteCompiler<'_, '_> { self.object_method(expr.into()); self.emit_opcode(Opcode::SetHomeObject); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); } PropertyName::Computed(name_node) => { self.compile_object_literal_computed_method( @@ -109,7 +109,7 @@ impl ByteCompiler<'_, '_> { self.object_method(expr.into()); self.emit_opcode(Opcode::SetHomeObject); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); } PropertyName::Computed(name_node) => { self.compile_object_literal_computed_method( @@ -124,7 +124,7 @@ impl ByteCompiler<'_, '_> { self.object_method(expr.into()); self.emit_opcode(Opcode::SetHomeObject); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::DefineOwnPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); } PropertyName::Computed(name_node) => { self.compile_object_literal_computed_method( @@ -140,7 +140,7 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::Swap); self.emit( Opcode::CopyDataProperties, - &[Operand::U32(0), Operand::U32(0)], + &[Operand::Varying(0), Operand::Varying(0)], ); self.emit_opcode(Opcode::Pop); } diff --git a/boa_engine/src/bytecompiler/expression/unary.rs b/boa_engine/src/bytecompiler/expression/unary.rs index e0dcf9a9374..662d403afc5 100644 --- a/boa_engine/src/bytecompiler/expression/unary.rs +++ b/boa_engine/src/bytecompiler/expression/unary.rs @@ -4,7 +4,7 @@ use boa_ast::{ }; use crate::{ - bytecompiler::{Access, ByteCompiler, Operand}, + bytecompiler::{Access, ByteCompiler}, vm::Opcode, }; @@ -29,7 +29,7 @@ impl ByteCompiler<'_, '_> { Expression::Identifier(identifier) => { let binding = self.get_binding_value(*identifier); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::GetNameOrUndefined, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetNameOrUndefined, index); } expr => self.compile_expr(expr, true), } diff --git a/boa_engine/src/bytecompiler/expression/update.rs b/boa_engine/src/bytecompiler/expression/update.rs index 94fd17dde79..110cc6b4400 100644 --- a/boa_engine/src/bytecompiler/expression/update.rs +++ b/boa_engine/src/bytecompiler/expression/update.rs @@ -28,9 +28,9 @@ impl ByteCompiler<'_, '_> { let lex = self.current_environment.is_lex_binding(name); if lex { - self.emit(Opcode::GetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetName, index); } else { - self.emit(Opcode::GetNameAndLocator, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetNameAndLocator, index); } self.emit_opcode(opcode); @@ -44,11 +44,11 @@ impl ByteCompiler<'_, '_> { match self.set_mutable_binding(name) { Ok(binding) => { let index = self.get_or_insert_binding(binding); - self.emit(Opcode::SetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetName, index); } Err(BindingLocatorError::MutateImmutable) => { let index = self.get_or_insert_name(name); - self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index); } Err(BindingLocatorError::Silent) => { self.emit_opcode(Opcode::Pop); @@ -67,13 +67,13 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); self.emit_opcode(opcode); if post { self.emit(Opcode::RotateRight, &[Operand::U8(4)]); } - self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPropertyByName, index); if post { self.emit_opcode(Opcode::Pop); } @@ -102,13 +102,13 @@ impl ByteCompiler<'_, '_> { self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); - self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPrivateField, index); self.emit_opcode(opcode); if post { self.emit(Opcode::RotateRight, &[Operand::U8(3)]); } - self.emit(Opcode::SetPrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPrivateField, index); if post { self.emit_opcode(Opcode::Pop); } @@ -122,13 +122,13 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::Swap); self.emit_opcode(Opcode::This); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); self.emit_opcode(opcode); if post { self.emit(Opcode::RotateRight, &[Operand::U8(3)]); } - self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPropertyByName, index); if post { self.emit_opcode(Opcode::Pop); } diff --git a/boa_engine/src/bytecompiler/mod.rs b/boa_engine/src/bytecompiler/mod.rs index f26546f938a..90fc0ada5e4 100644 --- a/boa_engine/src/bytecompiler/mod.rs +++ b/boa_engine/src/bytecompiler/mod.rs @@ -17,7 +17,10 @@ use crate::{ builtins::function::ThisMode, environments::{BindingLocator, BindingLocatorError, CompileTimeEnvironment}, js_string, - vm::{BindingOpcode, CodeBlock, CodeBlockFlags, GeneratorResumeKind, Handler, Opcode}, + vm::{ + BindingOpcode, CodeBlock, CodeBlockFlags, GeneratorResumeKind, Handler, Opcode, + VaryingOperandKind, + }, Context, JsBigInt, JsString, JsValue, }; use boa_ast::{ @@ -223,6 +226,7 @@ pub(crate) enum Operand { U32(u32), I64(i64), U64(u64), + Varying(u32), } /// The [`ByteCompiler`] is used to compile ECMAScript AST from [`boa_ast`] to bytecode. @@ -406,18 +410,18 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { BindingOpcode::Var => { let binding = self.initialize_mutable_binding(name, true); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::DefVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefVar, index); } BindingOpcode::InitVar => { if self.has_binding(name) { match self.set_mutable_binding(name) { Ok(binding) => { let index = self.get_or_insert_binding(binding); - self.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefInitVar, index); } Err(BindingLocatorError::MutateImmutable) => { let index = self.get_or_insert_name(name); - self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index); } Err(BindingLocatorError::Silent) => { self.emit_opcode(Opcode::Pop); @@ -426,27 +430,27 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { } else { let binding = self.initialize_mutable_binding(name, true); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefInitVar, index); }; } BindingOpcode::InitLet => { let binding = self.initialize_mutable_binding(name, false); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::PutLexicalValue, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::PutLexicalValue, index); } BindingOpcode::InitConst => { let binding = self.initialize_immutable_binding(name); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::PutLexicalValue, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::PutLexicalValue, index); } BindingOpcode::SetName => match self.set_mutable_binding(name) { Ok(binding) => { let index = self.get_or_insert_binding(binding); - self.emit(Opcode::SetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetName, index); } Err(BindingLocatorError::MutateImmutable) => { let index = self.get_or_insert_name(name); - self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index); } Err(BindingLocatorError::Silent) => { self.emit_opcode(Opcode::Pop); @@ -461,13 +465,49 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { } pub(crate) fn emit(&mut self, opcode: Opcode, operands: &[Operand]) { + let mut varying_kind = VaryingOperandKind::U8; + for operand in operands { + if let Operand::Varying(operand) = *operand { + if u8::try_from(operand).is_ok() { + } else if u16::try_from(operand).is_ok() { + varying_kind = VaryingOperandKind::U16; + } else { + varying_kind = VaryingOperandKind::U32; + break; + } + } + } + + match varying_kind { + VaryingOperandKind::U8 => {} + VaryingOperandKind::U16 => self.emit_opcode(Opcode::U16Operands), + VaryingOperandKind::U32 => self.emit_opcode(Opcode::U32Operands), + } self.emit_opcode(opcode); for operand in operands { - self.emit_operand(*operand); + self.emit_operand(*operand, varying_kind); } } - pub(crate) fn emit_operand(&mut self, operand: Operand) { + /// Emits an opcode with one varying operand. + /// + /// Simpler version of [`ByteCompiler::emit()`]. + pub(crate) fn emit_with_varying_operand(&mut self, opcode: Opcode, operand: u32) { + if let Ok(operand) = u8::try_from(operand) { + self.emit_opcode(opcode); + self.emit_u8(operand); + } else if let Ok(operand) = u16::try_from(operand) { + self.emit_opcode(Opcode::U16Operands); + self.emit_opcode(opcode); + self.emit_u16(operand); + } else { + self.emit_opcode(Opcode::U32Operands); + self.emit_opcode(opcode); + self.emit_u32(operand); + } + } + + pub(crate) fn emit_operand(&mut self, operand: Operand, varying_kind: VaryingOperandKind) { match operand { Operand::Bool(v) => self.emit_u8(v.into()), Operand::I8(v) => self.emit_i8(v), @@ -478,6 +518,11 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { Operand::U32(v) => self.emit_u32(v), Operand::I64(v) => self.emit_i64(v), Operand::U64(v) => self.emit_u64(v), + Operand::Varying(v) => match varying_kind { + VaryingOperandKind::U8 => self.emit_u8(v as u8), + VaryingOperandKind::U16 => self.emit_u16(v as u16), + VaryingOperandKind::U32 => self.emit_u32(v), + }, } } @@ -533,7 +578,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { fn emit_push_literal(&mut self, literal: Literal) { let index = self.get_or_insert_literal(literal); - self.emit(Opcode::PushLiteral, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::PushLiteral, index); } fn emit_push_rational(&mut self, value: f64) { @@ -655,7 +700,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { Access::Variable { name } => { let binding = self.get_binding_value(name); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::GetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetName, index); } Access::Property { access } => match access { PropertyAccess::Simple(access) => match access.field() { @@ -663,7 +708,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { let index = self.get_or_insert_name((*name).into()); self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); } PropertyAccessField::Expr(expr) => { self.compile_expr(access.target(), true); @@ -675,14 +720,14 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { PropertyAccess::Private(access) => { let index = self.get_or_insert_private_name(access.field()); self.compile_expr(access.target(), true); - self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPrivateField, index); } PropertyAccess::Super(access) => match access.field() { PropertyAccessField::Const(field) => { let index = self.get_or_insert_name((*field).into()); self.emit_opcode(Opcode::Super); self.emit_opcode(Opcode::This); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); } PropertyAccessField::Expr(expr) => { self.emit_opcode(Opcode::Super); @@ -723,7 +768,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { let lex = self.current_environment.is_lex_binding(name); if !lex { - self.emit(Opcode::GetLocator, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetLocator, index); } expr_fn(self, 0); @@ -735,11 +780,11 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { match self.set_mutable_binding(name) { Ok(binding) => { let index = self.get_or_insert_binding(binding); - self.emit(Opcode::SetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetName, index); } Err(BindingLocatorError::MutateImmutable) => { let index = self.get_or_insert_name(name); - self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index); } Err(BindingLocatorError::Silent) => { self.emit_opcode(Opcode::Pop); @@ -757,7 +802,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { expr_fn(self, 2); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPropertyByName, index); if !use_expr { self.emit_opcode(Opcode::Pop); } @@ -777,7 +822,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { self.compile_expr(access.target(), true); expr_fn(self, 1); let index = self.get_or_insert_private_name(access.field()); - self.emit(Opcode::SetPrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPrivateField, index); if !use_expr { self.emit_opcode(Opcode::Pop); } @@ -788,7 +833,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { self.emit_opcode(Opcode::This); expr_fn(self, 1); let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::SetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetPropertyByName, index); if !use_expr { self.emit_opcode(Opcode::Pop); } @@ -816,7 +861,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { PropertyAccessField::Const(name) => { let index = self.get_or_insert_name((*name).into()); self.compile_expr(access.target(), true); - self.emit(Opcode::DeletePropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DeletePropertyByName, index); } PropertyAccessField::Expr(expr) => { self.compile_expr(access.target(), true); @@ -833,7 +878,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { Access::Variable { name } => { let binding = self.get_binding_value(name); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::DeleteName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DeleteName, index); } Access::This => { self.emit_opcode(Opcode::PushTrue); @@ -895,7 +940,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { match access.field() { PropertyAccessField::Const(field) => { let index = self.get_or_insert_name((*field).into()); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); } PropertyAccessField::Expr(field) => { self.compile_expr(field, true); @@ -907,7 +952,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { self.compile_expr(access.target(), true); self.emit_opcode(Opcode::Dup); let index = self.get_or_insert_private_name(access.field()); - self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPrivateField, index); } PropertyAccess::Super(access) => { self.emit_opcode(Opcode::This); @@ -916,7 +961,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { match access.field() { PropertyAccessField::Const(field) => { let index = self.get_or_insert_name((*field).into()); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); } PropertyAccessField::Expr(expr) => { self.compile_expr(expr, true); @@ -1002,7 +1047,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { match field { PropertyAccessField::Const(name) => { let index = self.get_or_insert_name((*name).into()); - self.emit(Opcode::GetPropertyByName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPropertyByName, index); } PropertyAccessField::Expr(expr) => { self.compile_expr(expr, true); @@ -1015,7 +1060,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { OptionalOperationKind::PrivatePropertyAccess { field } => { self.emit_opcode(Opcode::Dup); let index = self.get_or_insert_private_name(*field); - self.emit(Opcode::GetPrivateField, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetPrivateField, index); self.emit(Opcode::RotateLeft, &[Operand::U8(3)]); self.emit_opcode(Opcode::Pop); } @@ -1039,7 +1084,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { for arg in args { self.compile_expr(arg, true); } - self.emit(Opcode::Call, &[Operand::U32(args.len() as u32)]); + self.emit_with_varying_operand(Opcode::Call, args.len() as u32); } self.emit_opcode(Opcode::PushUndefined); @@ -1148,16 +1193,16 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { if self.annex_b_function_names.contains(&name) { let binding = self.get_binding_value(name); let index = self.get_or_insert_binding(binding); - self.emit(Opcode::GetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetName, index); match self.set_mutable_binding_var(name) { Ok(binding) => { let index = self.get_or_insert_binding(binding); - self.emit(Opcode::SetName, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::SetName, index); } Err(BindingLocatorError::MutateImmutable) => { let index = self.get_or_insert_name(name); - self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index); } Err(BindingLocatorError::Silent) => { self.emit_opcode(Opcode::Pop); @@ -1235,28 +1280,22 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { let index = self.function(function); if r#async && generator { - self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); } else if generator { - self.emit(Opcode::GetGenerator, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetGenerator, index); } else if r#async && arrow { - self.emit( - Opcode::GetAsyncArrowFunction, - &[Operand::U32(index), Operand::Bool(false)], - ); + self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]); } else if r#async { self.emit( Opcode::GetFunctionAsync, - &[Operand::U32(index), Operand::Bool(false)], + &[Operand::Varying(index), Operand::Bool(false)], ); } else if arrow { - self.emit( - Opcode::GetArrowFunction, - &[Operand::U32(index), Operand::Bool(false)], - ); + self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]); } else { self.emit( Opcode::GetFunction, - &[Operand::U32(index), Operand::Bool(false)], + &[Operand::Varying(index), Operand::Bool(false)], ); } @@ -1318,28 +1357,22 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { self.functions.push(code); if r#async && generator { - self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); } else if generator { - self.emit(Opcode::GetGenerator, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetGenerator, index); } else if r#async && arrow { - self.emit( - Opcode::GetAsyncArrowFunction, - &[Operand::U32(index), Operand::Bool(true)], - ); + self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]); } else if r#async { self.emit( Opcode::GetFunctionAsync, - &[Operand::U32(index), Operand::Bool(true)], + &[Operand::Varying(index), Operand::Bool(true)], ); } else if arrow { - self.emit( - Opcode::GetArrowFunction, - &[Operand::U32(index), Operand::Bool(true)], - ); + self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]); } else { self.emit( Opcode::GetFunction, - &[Operand::U32(index), Operand::Bool(true)], + &[Operand::Varying(index), Operand::Bool(true)], ); } } @@ -1388,28 +1421,22 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { self.functions.push(code); if r#async && generator { - self.emit(Opcode::GetGeneratorAsync, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); } else if generator { - self.emit(Opcode::GetGenerator, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::GetGenerator, index); } else if r#async && arrow { - self.emit( - Opcode::GetAsyncArrowFunction, - &[Operand::U32(index), Operand::Bool(true)], - ); + self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]); } else if r#async { self.emit( Opcode::GetFunctionAsync, - &[Operand::U32(index), Operand::Bool(true)], + &[Operand::Varying(index), Operand::Bool(true)], ); } else if arrow { - self.emit( - Opcode::GetArrowFunction, - &[Operand::U32(index), Operand::Bool(true)], - ); + self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]); } else { self.emit( Opcode::GetFunction, - &[Operand::U32(index), Operand::Bool(true)], + &[Operand::Varying(index), Operand::Bool(true)], ); } } @@ -1474,12 +1501,14 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { match kind { CallKind::CallEval if contains_spread => self.emit_opcode(Opcode::CallEvalSpread), CallKind::CallEval => { - self.emit(Opcode::CallEval, &[Operand::U32(call.args().len() as u32)]); + self.emit_with_varying_operand(Opcode::CallEval, call.args().len() as u32); } CallKind::Call if contains_spread => self.emit_opcode(Opcode::CallSpread), - CallKind::Call => self.emit(Opcode::Call, &[Operand::U32(call.args().len() as u32)]), + CallKind::Call => { + self.emit_with_varying_operand(Opcode::Call, call.args().len() as u32); + } CallKind::New if contains_spread => self.emit_opcode(Opcode::NewSpread), - CallKind::New => self.emit(Opcode::New, &[Operand::U32(call.args().len() as u32)]), + CallKind::New => self.emit_with_varying_operand(Opcode::New, call.args().len() as u32), } if !use_expr { diff --git a/boa_engine/src/bytecompiler/statement/loop.rs b/boa_engine/src/bytecompiler/statement/loop.rs index fc78ab8ee61..3196513e63a 100644 --- a/boa_engine/src/bytecompiler/statement/loop.rs +++ b/boa_engine/src/bytecompiler/statement/loop.rs @@ -69,13 +69,13 @@ impl ByteCompiler<'_, '_> { if let Some(let_binding_indices) = let_binding_indices { for index in &let_binding_indices { - self.emit(Opcode::GetName, &[Operand::U32(*index)]); + self.emit_with_varying_operand(Opcode::GetName, *index); } self.emit_opcode(Opcode::PopEnvironment); iteration_env_labels = Some(self.emit_opcode_with_operand(Opcode::PushDeclarativeEnvironment)); for index in let_binding_indices.iter().rev() { - self.emit(Opcode::PutLexicalValue, &[Operand::U32(*index)]); + self.emit_with_varying_operand(Opcode::PutLexicalValue, *index); } } @@ -303,11 +303,11 @@ impl ByteCompiler<'_, '_> { match self.set_mutable_binding(*ident) { Ok(binding) => { let index = self.get_or_insert_binding(binding); - self.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::DefInitVar, index); } Err(BindingLocatorError::MutateImmutable) => { let index = self.get_or_insert_name(*ident); - self.emit(Opcode::ThrowMutateImmutable, &[Operand::U32(index)]); + self.emit_with_varying_operand(Opcode::ThrowMutateImmutable, index); } Err(BindingLocatorError::Silent) => { self.emit_opcode(Opcode::Pop); diff --git a/boa_engine/src/bytecompiler/utils.rs b/boa_engine/src/bytecompiler/utils.rs index 6bcd340dd24..6ba4335fe2c 100644 --- a/boa_engine/src/bytecompiler/utils.rs +++ b/boa_engine/src/bytecompiler/utils.rs @@ -36,7 +36,7 @@ impl ByteCompiler<'_, '_> { let error_msg = self.get_or_insert_literal(Literal::String(js_string!( "inner result was not an object" ))); - self.emit(Opcode::ThrowNewTypeError, &[Operand::U32(error_msg)]); + self.emit_with_varying_operand(Opcode::ThrowNewTypeError, error_msg); self.patch_jump(skip_return); self.emit_opcode(Opcode::IteratorPop); diff --git a/boa_engine/src/module/source.rs b/boa_engine/src/module/source.rs index b07132261ee..068ba259efa 100644 --- a/boa_engine/src/module/source.rs +++ b/boa_engine/src/module/source.rs @@ -22,7 +22,7 @@ use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; use crate::{ builtins::{promise::PromiseCapability, Promise}, - bytecompiler::{ByteCompiler, FunctionSpec, Operand}, + bytecompiler::{ByteCompiler, FunctionSpec}, environments::{BindingLocator, CompileTimeEnvironment, EnvironmentStack}, module::ModuleKind, object::{FunctionObjectBuilder, JsPromise, RecursionLimiter}, @@ -1501,7 +1501,7 @@ impl SourceTextModule { let binding = compiler.initialize_mutable_binding(name, false); let index = compiler.get_or_insert_binding(binding); compiler.emit_opcode(Opcode::PushUndefined); - compiler.emit(Opcode::DefInitVar, &[Operand::U32(index)]); + compiler.emit_with_varying_operand(Opcode::DefInitVar, index); // 3. Append dn to declaredVarNames. declared_var_names.push(name); } diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index aa689f7b212..005a8d19985 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -21,7 +21,8 @@ use std::{cell::Cell, mem::size_of, rc::Rc}; use thin_vec::ThinVec; #[cfg(any(feature = "trace", feature = "flowgraph"))] -use crate::vm::Opcode; +use super::{Instruction, InstructionIterator}; + #[cfg(any(feature = "trace", feature = "flowgraph"))] use boa_interner::{Interner, ToInternedString}; @@ -299,10 +300,11 @@ impl CodeBlock { /// /// Returns an empty `String` if no operands are present. #[cfg(any(feature = "trace", feature = "flowgraph"))] - pub(crate) fn instruction_operands(&self, pc: &mut usize, interner: &Interner) -> String { - use super::Instruction; - - let instruction = Instruction::from_bytecode(&self.bytecode, pc); + pub(crate) fn instruction_operands( + &self, + instruction: &Instruction, + interner: &Interner, + ) -> String { match instruction { Instruction::SetFunctionName { prefix } => match prefix { 0 => "prefix: none", @@ -318,11 +320,11 @@ impl CodeBlock { Instruction::PushInt8 { value } => value.to_string(), Instruction::PushInt16 { value } => value.to_string(), Instruction::PushInt32 { value } => value.to_string(), - Instruction::PushFloat { value } => ryu_js::Buffer::new().format(value).to_string(), - Instruction::PushDouble { value } => ryu_js::Buffer::new().format(value).to_string(), - Instruction::PushLiteral { index: value } - | Instruction::ThrowNewTypeError { message: value } - | Instruction::Jump { address: value } + Instruction::PushFloat { value } => ryu_js::Buffer::new().format(*value).to_string(), + Instruction::PushDouble { value } => ryu_js::Buffer::new().format(*value).to_string(), + Instruction::PushLiteral { index } + | Instruction::ThrowNewTypeError { message: index } => index.value().to_string(), + Instruction::Jump { address: value } | Instruction::JumpIfTrue { address: value } | Instruction::JumpIfFalse { address: value } | Instruction::JumpIfNotUndefined { address: value } @@ -331,8 +333,8 @@ impl CodeBlock { | Instruction::Default { address: value } | Instruction::LogicalAnd { exit: value } | Instruction::LogicalOr { exit: value } - | Instruction::Coalesce { exit: value } - | Instruction::CallEval { + | Instruction::Coalesce { exit: value } => value.to_string(), + Instruction::CallEval { argument_count: value, } | Instruction::Call { @@ -344,7 +346,7 @@ impl CodeBlock { | Instruction::SuperCall { argument_count: value, } - | Instruction::ConcatToString { value_count: value } => value.to_string(), + | Instruction::ConcatToString { value_count: value } => value.value().to_string(), Instruction::PushDeclarativeEnvironment { compile_environments_index, } @@ -354,8 +356,8 @@ impl CodeBlock { Instruction::CopyDataProperties { excluded_key_count: value1, excluded_key_count_computed: value2, - } - | Instruction::GeneratorDelegateNext { + } => format!("{}, {}", value1.value(), value2.value()), + Instruction::GeneratorDelegateNext { return_method_undefined: value1, throw_method_undefined: value2, } @@ -365,29 +367,28 @@ impl CodeBlock { } => { format!("{value1}, {value2}") } - Instruction::TemplateLookup { exit: value, site } - | Instruction::TemplateCreate { count: value, site } => { - format!("{value}, {site}") + Instruction::TemplateLookup { exit: value, site } => format!("{value}, {site}"), + Instruction::TemplateCreate { count, site } => { + format!("{}, {site}", count.value()) } - Instruction::GetArrowFunction { index, method } - | Instruction::GetAsyncArrowFunction { index, method } - | Instruction::GetFunction { index, method } + Instruction::GetFunction { index, method } | Instruction::GetFunctionAsync { index, method } => { + let index = index.value() as usize; format!( "{index:04}: '{}' (length: {}), method: {method}", - self.functions[index as usize] - .name() - .to_std_string_escaped(), - self.functions[index as usize].length + self.functions[index].name().to_std_string_escaped(), + self.functions[index].length ) } - Instruction::GetGenerator { index } | Instruction::GetGeneratorAsync { index } => { + Instruction::GetArrowFunction { index } + | Instruction::GetAsyncArrowFunction { index } + | Instruction::GetGenerator { index } + | Instruction::GetGeneratorAsync { index } => { + let index = index.value() as usize; format!( "{index:04}: '{}' (length: {})", - self.functions[index as usize] - .name() - .to_std_string_escaped(), - self.functions[index as usize].length + self.functions[index].name().to_std_string_escaped(), + self.functions[index].length ) } Instruction::DefVar { index } @@ -400,12 +401,12 @@ impl CodeBlock { | Instruction::SetName { index } | Instruction::DeleteName { index } => { format!( - "{index:04}: '{}'", - interner.resolve_expect(self.bindings[index as usize].name().sym()), + "{:04}: '{}'", + index.value(), + interner.resolve_expect(self.bindings[index.value() as usize].name().sym()), ) } Instruction::GetPropertyByName { index } - | Instruction::GetMethod { index } | Instruction::SetPropertyByName { index } | Instruction::DefineOwnPropertyByName { index } | Instruction::DefineClassStaticMethodByName { index } @@ -416,6 +417,8 @@ impl CodeBlock { | Instruction::SetPropertySetterByName { index } | Instruction::DefineClassStaticSetterByName { index } | Instruction::DefineClassSetterByName { index } + | Instruction::InPrivate { index } + | Instruction::ThrowMutateImmutable { index } | Instruction::DeletePropertyByName { index } | Instruction::SetPrivateField { index } | Instruction::DefinePrivateField { index } @@ -426,12 +429,11 @@ impl CodeBlock { | Instruction::PushClassFieldPrivate { index } | Instruction::PushClassPrivateGetter { index } | Instruction::PushClassPrivateSetter { index } - | Instruction::PushClassPrivateMethod { index } - | Instruction::InPrivate { index } - | Instruction::ThrowMutateImmutable { index } => { + | Instruction::PushClassPrivateMethod { index } => { format!( - "{index:04}: '{}'", - self.names[index as usize].to_std_string_escaped(), + "{:04}: '{}'", + index.value(), + self.names[index.value() as usize].to_std_string_escaped(), ) } Instruction::PushPrivateEnvironment { name_indices } => { @@ -571,7 +573,10 @@ impl CodeBlock { | Instruction::GetReturnValue | Instruction::SetReturnValue | Instruction::Nop => String::new(), - Instruction::Reserved1 + + Instruction::U16Operands + | Instruction::U32Operands + | Instruction::Reserved1 | Instruction::Reserved2 | Instruction::Reserved3 | Instruction::Reserved4 @@ -627,8 +632,7 @@ impl CodeBlock { | Instruction::Reserved54 | Instruction::Reserved55 | Instruction::Reserved56 - | Instruction::Reserved57 - | Instruction::Reserved58 => unreachable!("Reserved opcodes are unrechable"), + | Instruction::Reserved57 => unreachable!("Reserved opcodes are unrechable"), } } } @@ -648,15 +652,14 @@ impl ToInternedString for CodeBlock { format!("Compiled Output: '{}'", name.to_std_string_escaped()), )); - let mut pc = 0; - let mut count = 0; - while pc < self.bytecode.len() { - let instruction_start_pc = pc; + let mut iterator = InstructionIterator::new(&self.bytecode); - let opcode: Opcode = self.bytecode[instruction_start_pc].into(); - let opcode = opcode.as_str(); - let previous_pc = pc; - let operands = self.instruction_operands(&mut pc, interner); + let mut count = 0; + while let Some((instruction_start_pc, varying_operand_kind, instruction)) = iterator.next() + { + let opcode = instruction.opcode().as_str(); + let operands = self.instruction_operands(&instruction, interner); + let pc = iterator.pc(); let handler = if let Some((i, handler)) = self.find_handler(instruction_start_pc as u32) { @@ -672,8 +675,14 @@ impl ToInternedString for CodeBlock { " none ".to_string() }; + let varying_operand_kind = match varying_operand_kind { + super::VaryingOperandKind::U8 => "", + super::VaryingOperandKind::U16 => ".U16", + super::VaryingOperandKind::U32 => ".U32", + }; + f.push_str(&format!( - "{previous_pc:06} {count:04} {handler} {opcode:<27}{operands}\n", + "{instruction_start_pc:06} {count:04} {handler} {opcode}{varying_operand_kind:<27}{operands}\n", )); count += 1; } diff --git a/boa_engine/src/vm/flowgraph/mod.rs b/boa_engine/src/vm/flowgraph/mod.rs index a6b05f08803..02c5fbbcd71 100644 --- a/boa_engine/src/vm/flowgraph/mod.rs +++ b/boa_engine/src/vm/flowgraph/mod.rs @@ -14,7 +14,7 @@ pub use edge::*; pub use graph::*; pub use node::*; -use super::Instruction; +use super::{Instruction, InstructionIterator}; impl CodeBlock { /// Output the [`CodeBlock`] VM instructions into a [`Graph`]. @@ -29,19 +29,18 @@ impl CodeBlock { graph.set_label(name); - let mut pc = 0; - while pc < self.bytecode.len() { - let previous_pc = pc; - let instruction = Instruction::from_bytecode(&self.bytecode, &mut pc); + let mut iterator = InstructionIterator::new(&self.bytecode); + while let Some((previous_pc, _, instruction)) = iterator.next() { let opcode = instruction.opcode(); let opcode_str = opcode.as_str(); - let mut tmp = previous_pc; let label = format!( "{opcode_str} {}", - self.instruction_operands(&mut tmp, interner) + self.instruction_operands(&instruction, interner) ); + let pc = iterator.pc(); + match instruction { Instruction::SetFunctionName { .. } => { graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); @@ -77,11 +76,7 @@ impl CodeBlock { graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); } - Instruction::PushLiteral { index } => { - let operand_str = self.literals[index as usize].display().to_string(); - let operand_str = operand_str.escape_debug(); - let label = format!("{opcode_str} {operand_str}"); - + Instruction::PushLiteral { .. } => { graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); } @@ -271,7 +266,6 @@ impl CodeBlock { graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); } Instruction::GetPropertyByName { .. } - | Instruction::GetMethod { .. } | Instruction::SetPropertyByName { .. } | Instruction::DefineOwnPropertyByName { .. } | Instruction::DefineClassStaticMethodByName { .. } @@ -471,7 +465,9 @@ impl CodeBlock { Instruction::Return => { graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::Red); } - Instruction::Reserved1 + Instruction::U16Operands + | Instruction::U32Operands + | Instruction::Reserved1 | Instruction::Reserved2 | Instruction::Reserved3 | Instruction::Reserved4 @@ -527,8 +523,7 @@ impl CodeBlock { | Instruction::Reserved54 | Instruction::Reserved55 | Instruction::Reserved56 - | Instruction::Reserved57 - | Instruction::Reserved58 => unreachable!("Reserved opcodes are unrechable"), + | Instruction::Reserved57 => unreachable!("Reserved opcodes are unrechable"), } } diff --git a/boa_engine/src/vm/mod.rs b/boa_engine/src/vm/mod.rs index bbce9310e98..ee3b2e8f7c1 100644 --- a/boa_engine/src/vm/mod.rs +++ b/boa_engine/src/vm/mod.rs @@ -32,11 +32,11 @@ mod runtime_limits; #[cfg(feature = "flowgraph")] pub mod flowgraph; +pub(crate) use opcode::{Instruction, InstructionIterator, Opcode, VaryingOperandKind}; pub use runtime_limits::RuntimeLimits; pub use { call_frame::{CallFrame, GeneratorResumeKind}, code_block::CodeBlock, - opcode::{Instruction, InstructionIterator, Opcode}, }; pub(crate) use { @@ -246,13 +246,16 @@ impl Context<'_> { } fn trace_execute_instruction(&mut self) -> JsResult { - let mut pc = self.vm.frame().pc as usize; - let opcode: Opcode = self.vm.frame().code_block.read::(pc).into(); + let bytecodes = &self.vm.frame().code_block.bytecode; + let pc = self.vm.frame().pc as usize; + let (_, varying_operand_kind, instruction) = InstructionIterator::with_pc(bytecodes, pc) + .next() + .expect("There should be an instruction left"); let operands = self .vm .frame() .code_block - .instruction_operands(&mut pc, self.interner()); + .instruction_operands(&instruction, self.interner()); let instant = Instant::now(); let result = self.execute_instruction(); @@ -279,10 +282,17 @@ impl Context<'_> { stack }; + let varying_operand_kind = match varying_operand_kind { + VaryingOperandKind::U8 => "", + VaryingOperandKind::U16 => ".U16", + VaryingOperandKind::U32 => ".U32", + }; + println!( - "{:) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl InPrivate { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let rhs = context.vm.pop(); let Some(rhs) = rhs.as_object() else { @@ -138,6 +134,26 @@ impl Operation for InPrivate { } } +impl Operation for InPrivate { + const NAME: &'static str = "InPrivate"; + const INSTRUCTION: &'static str = "INST - InPrivate"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `InstanceOf` implements the Opcode Operation for `Opcode::InstanceOf` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/call/mod.rs b/boa_engine/src/vm/opcode/call/mod.rs index 6002dafc9e5..453965713a5 100644 --- a/boa_engine/src/vm/opcode/call/mod.rs +++ b/boa_engine/src/vm/opcode/call/mod.rs @@ -14,11 +14,8 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct CallEval; -impl Operation for CallEval { - const NAME: &'static str = "CallEval"; - const INSTRUCTION: &'static str = "INST - CallEval"; - - fn execute(context: &mut Context<'_>) -> JsResult { +impl CallEval { + fn operation(context: &mut Context<'_>, argument_count: usize) -> JsResult { if context.vm.runtime_limits.recursion_limit() <= context.vm.frames.len() { return Err(JsNativeError::runtime_limit() .with_message(format!( @@ -32,8 +29,7 @@ impl Operation for CallEval { .with_message("Maximum call stack size exceeded") .into()); } - let argument_count = context.vm.read::(); - let mut arguments = Vec::with_capacity(argument_count as usize); + let mut arguments = Vec::with_capacity(argument_count); for _ in 0..argument_count { arguments.push(context.vm.pop()); } @@ -75,6 +71,26 @@ impl Operation for CallEval { } } +impl Operation for CallEval { + const NAME: &'static str = "CallEval"; + const INSTRUCTION: &'static str = "INST - CallEval"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let argument_count = context.vm.read::(); + Self::operation(context, argument_count as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let argument_count = context.vm.read::() as usize; + Self::operation(context, argument_count) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let argument_count = context.vm.read::(); + Self::operation(context, argument_count as usize) + } +} + /// `CallEvalSpread` implements the Opcode Operation for `Opcode::CallEvalSpread` /// /// Operation: @@ -156,11 +172,8 @@ impl Operation for CallEvalSpread { #[derive(Debug, Clone, Copy)] pub(crate) struct Call; -impl Operation for Call { - const NAME: &'static str = "Call"; - const INSTRUCTION: &'static str = "INST - Call"; - - fn execute(context: &mut Context<'_>) -> JsResult { +impl Call { + fn operation(context: &mut Context<'_>, argument_count: usize) -> JsResult { if context.vm.runtime_limits.recursion_limit() <= context.vm.frames.len() { return Err(JsNativeError::runtime_limit() .with_message(format!( @@ -174,8 +187,7 @@ impl Operation for Call { .with_message("Maximum call stack size exceeded") .into()); } - let argument_count = context.vm.read::(); - let mut arguments = Vec::with_capacity(argument_count as usize); + let mut arguments = Vec::with_capacity(argument_count); for _ in 0..argument_count { arguments.push(context.vm.pop()); } @@ -200,6 +212,26 @@ impl Operation for Call { } } +impl Operation for Call { + const NAME: &'static str = "Call"; + const INSTRUCTION: &'static str = "INST - Call"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let argument_count = context.vm.read::(); + Self::operation(context, argument_count as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let argument_count = context.vm.read::() as usize; + Self::operation(context, argument_count) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let argument_count = context.vm.read::(); + Self::operation(context, argument_count as usize) + } +} + #[derive(Debug, Clone, Copy)] pub(crate) struct CallSpread; diff --git a/boa_engine/src/vm/opcode/concat/mod.rs b/boa_engine/src/vm/opcode/concat/mod.rs index 8a526122c19..5ebb102f8c3 100644 --- a/boa_engine/src/vm/opcode/concat/mod.rs +++ b/boa_engine/src/vm/opcode/concat/mod.rs @@ -10,13 +10,9 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct ConcatToString; -impl Operation for ConcatToString { - const NAME: &'static str = "ConcatToString"; - const INSTRUCTION: &'static str = "INST - ConcatToString"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let value_count = context.vm.read::(); - let mut strings = Vec::with_capacity(value_count as usize); +impl ConcatToString { + fn operation(context: &mut Context<'_>, value_count: usize) -> JsResult { + let mut strings = Vec::with_capacity(value_count); for _ in 0..value_count { strings.push(context.vm.pop().to_string(context)?); } @@ -31,3 +27,23 @@ impl Operation for ConcatToString { Ok(CompletionType::Normal) } } + +impl Operation for ConcatToString { + const NAME: &'static str = "ConcatToString"; + const INSTRUCTION: &'static str = "INST - ConcatToString"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let value_count = context.vm.read::() as usize; + Self::operation(context, value_count) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let value_count = context.vm.read::() as usize; + Self::operation(context, value_count) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let value_count = context.vm.read::() as usize; + Self::operation(context, value_count) + } +} diff --git a/boa_engine/src/vm/opcode/control_flow/throw.rs b/boa_engine/src/vm/opcode/control_flow/throw.rs index a9843ad8ec1..df09c646e72 100644 --- a/boa_engine/src/vm/opcode/control_flow/throw.rs +++ b/boa_engine/src/vm/opcode/control_flow/throw.rs @@ -117,13 +117,9 @@ impl Operation for MaybeException { #[derive(Debug, Clone, Copy)] pub(crate) struct ThrowNewTypeError; -impl Operation for ThrowNewTypeError { - const NAME: &'static str = "ThrowNewTypeError"; - const INSTRUCTION: &'static str = "INST - ThrowNewTypeError"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let msg = context.vm.frame().code_block.literals[index as usize] +impl ThrowNewTypeError { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let msg = context.vm.frame().code_block.literals[index] .as_string() .expect("throw message must be a string") .clone(); @@ -133,3 +129,23 @@ impl Operation for ThrowNewTypeError { Err(JsNativeError::typ().with_message(msg).into()) } } + +impl Operation for ThrowNewTypeError { + const NAME: &'static str = "ThrowNewTypeError"; + const INSTRUCTION: &'static str = "INST - ThrowNewTypeError"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} diff --git a/boa_engine/src/vm/opcode/copy/mod.rs b/boa_engine/src/vm/opcode/copy/mod.rs index 26a5626a9d3..d90ebd80c9c 100644 --- a/boa_engine/src/vm/opcode/copy/mod.rs +++ b/boa_engine/src/vm/opcode/copy/mod.rs @@ -10,14 +10,13 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct CopyDataProperties; -impl Operation for CopyDataProperties { - const NAME: &'static str = "CopyDataProperties"; - const INSTRUCTION: &'static str = "INST - CopyDataProperties"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let excluded_key_count = context.vm.read::(); - let excluded_key_count_computed = context.vm.read::(); - let mut excluded_keys = Vec::with_capacity(excluded_key_count as usize); +impl CopyDataProperties { + fn operation( + context: &mut Context<'_>, + excluded_key_count: usize, + excluded_key_count_computed: usize, + ) -> JsResult { + let mut excluded_keys = Vec::with_capacity(excluded_key_count); for _ in 0..excluded_key_count { let key = context.vm.pop(); excluded_keys.push( @@ -40,3 +39,26 @@ impl Operation for CopyDataProperties { Ok(CompletionType::Normal) } } + +impl Operation for CopyDataProperties { + const NAME: &'static str = "CopyDataProperties"; + const INSTRUCTION: &'static str = "INST - CopyDataProperties"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let excluded_key_count = context.vm.read::() as usize; + let excluded_key_count_computed = context.vm.read::() as usize; + Self::operation(context, excluded_key_count, excluded_key_count_computed) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let excluded_key_count = context.vm.read::() as usize; + let excluded_key_count_computed = context.vm.read::() as usize; + Self::operation(context, excluded_key_count, excluded_key_count_computed) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let excluded_key_count = context.vm.read::() as usize; + let excluded_key_count_computed = context.vm.read::() as usize; + Self::operation(context, excluded_key_count, excluded_key_count_computed) + } +} diff --git a/boa_engine/src/vm/opcode/define/class/getter.rs b/boa_engine/src/vm/opcode/define/class/getter.rs index 0766d7f4aff..de85969bc00 100644 --- a/boa_engine/src/vm/opcode/define/class/getter.rs +++ b/boa_engine/src/vm/opcode/define/class/getter.rs @@ -13,18 +13,12 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct DefineClassStaticGetterByName; -impl Operation for DefineClassStaticGetterByName { - const NAME: &'static str = "DefineClassStaticGetterByName"; - const INSTRUCTION: &'static str = "INST - DefineClassStaticGetterByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl DefineClassStaticGetterByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let function = context.vm.pop(); let class = context.vm.pop(); let class = class.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let key = context.vm.frame().code_block.names[index].clone().into(); { let function_object = function .as_object() @@ -56,6 +50,26 @@ impl Operation for DefineClassStaticGetterByName { } } +impl Operation for DefineClassStaticGetterByName { + const NAME: &'static str = "DefineClassStaticGetterByName"; + const INSTRUCTION: &'static str = "INST - DefineClassStaticGetterByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `DefineClassGetterByName` implements the Opcode Operation for `Opcode::DefineClassGetterByName` /// /// Operation: @@ -63,18 +77,12 @@ impl Operation for DefineClassStaticGetterByName { #[derive(Debug, Clone, Copy)] pub(crate) struct DefineClassGetterByName; -impl Operation for DefineClassGetterByName { - const NAME: &'static str = "DefineClassGetterByName"; - const INSTRUCTION: &'static str = "INST - DefineClassGetterByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl DefineClassGetterByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let function = context.vm.pop(); let class_proto = context.vm.pop(); let class_proto = class_proto.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let key = context.vm.frame().code_block.names[index].clone().into(); { let function_object = function .as_object() @@ -112,6 +120,26 @@ impl Operation for DefineClassGetterByName { } } +impl Operation for DefineClassGetterByName { + const NAME: &'static str = "DefineClassGetterByName"; + const INSTRUCTION: &'static str = "INST - DefineClassGetterByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `DefineClassStaticGetterByValue` implements the Opcode Operation for `Opcode::DefineClassStaticGetterByValue` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/define/class/method.rs b/boa_engine/src/vm/opcode/define/class/method.rs index 7601892cef0..13bd7677108 100644 --- a/boa_engine/src/vm/opcode/define/class/method.rs +++ b/boa_engine/src/vm/opcode/define/class/method.rs @@ -13,18 +13,12 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct DefineClassStaticMethodByName; -impl Operation for DefineClassStaticMethodByName { - const NAME: &'static str = "DefineClassStaticMethodByName"; - const INSTRUCTION: &'static str = "INST - DefineClassStaticMethodByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl DefineClassStaticMethodByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let function = context.vm.pop(); let class = context.vm.pop(); let class = class.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let key = context.vm.frame().code_block.names[index].clone().into(); { let function_object = function .as_object() @@ -52,6 +46,26 @@ impl Operation for DefineClassStaticMethodByName { } } +impl Operation for DefineClassStaticMethodByName { + const NAME: &'static str = "DefineClassStaticMethodByName"; + const INSTRUCTION: &'static str = "INST - DefineClassStaticMethodByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `DefineClassMethodByName` implements the Opcode Operation for `Opcode::DefineClassMethodByName` /// /// Operation: @@ -59,18 +73,12 @@ impl Operation for DefineClassStaticMethodByName { #[derive(Debug, Clone, Copy)] pub(crate) struct DefineClassMethodByName; -impl Operation for DefineClassMethodByName { - const NAME: &'static str = "DefineClassMethodByName"; - const INSTRUCTION: &'static str = "INST - DefineClassMethodByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl DefineClassMethodByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let function = context.vm.pop(); let class_proto = context.vm.pop(); let class_proto = class_proto.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let key = context.vm.frame().code_block.names[index].clone().into(); { let function_object = function .as_object() @@ -104,6 +112,26 @@ impl Operation for DefineClassMethodByName { } } +impl Operation for DefineClassMethodByName { + const NAME: &'static str = "DefineClassMethodByName"; + const INSTRUCTION: &'static str = "INST - DefineClassMethodByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `DefineClassStaticMethodByValue` implements the Opcode Operation for `Opcode::DefineClassStaticMethodByValue` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/define/class/setter.rs b/boa_engine/src/vm/opcode/define/class/setter.rs index 43f605a9c64..76056176293 100644 --- a/boa_engine/src/vm/opcode/define/class/setter.rs +++ b/boa_engine/src/vm/opcode/define/class/setter.rs @@ -13,18 +13,12 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct DefineClassStaticSetterByName; -impl Operation for DefineClassStaticSetterByName { - const NAME: &'static str = "DefineClassStaticSetterByName"; - const INSTRUCTION: &'static str = "INST - DefineClassStaticSetterByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl DefineClassStaticSetterByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let function = context.vm.pop(); let class = context.vm.pop(); let class = class.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let key = context.vm.frame().code_block.names[index].clone().into(); { let function_object = function .as_object() @@ -57,6 +51,26 @@ impl Operation for DefineClassStaticSetterByName { } } +impl Operation for DefineClassStaticSetterByName { + const NAME: &'static str = "DefineClassStaticSetterByName"; + const INSTRUCTION: &'static str = "INST - DefineClassStaticSetterByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `DefineClassSetterByName` implements the Opcode Operation for `Opcode::DefineClassSetterByName` /// /// Operation: @@ -64,18 +78,12 @@ impl Operation for DefineClassStaticSetterByName { #[derive(Debug, Clone, Copy)] pub(crate) struct DefineClassSetterByName; -impl Operation for DefineClassSetterByName { - const NAME: &'static str = "DefineClassSetterByName"; - const INSTRUCTION: &'static str = "INST - DefineClassSetterByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl DefineClassSetterByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let function = context.vm.pop(); let class_proto = context.vm.pop(); let class_proto = class_proto.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let key = context.vm.frame().code_block.names[index].clone().into(); { let function_object = function .as_object() @@ -115,6 +123,26 @@ impl Operation for DefineClassSetterByName { } } +impl Operation for DefineClassSetterByName { + const NAME: &'static str = "DefineClassSetterByName"; + const INSTRUCTION: &'static str = "INST - DefineClassSetterByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `DefineClassStaticSetterByValue` implements the Opcode Operation for `Opcode::DefineClassStaticSetterByValue` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/define/mod.rs b/boa_engine/src/vm/opcode/define/mod.rs index 83baeced5f9..cf77d02dce3 100644 --- a/boa_engine/src/vm/opcode/define/mod.rs +++ b/boa_engine/src/vm/opcode/define/mod.rs @@ -16,14 +16,11 @@ pub(crate) use own_property::*; #[derive(Debug, Clone, Copy)] pub(crate) struct DefVar; -impl Operation for DefVar { - const NAME: &'static str = "DefVar"; - const INSTRUCTION: &'static str = "INST - DefVar"; - - fn execute(context: &mut Context<'_>) -> JsResult { +impl DefVar { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { // TODO: spec specifies to return `empty` on empty vars, but we're trying to initialize. - let index = context.vm.read::(); - let binding_locator = context.vm.frame().code_block.bindings[index as usize]; + let binding_locator = context.vm.frame().code_block.bindings[index]; if binding_locator.is_global() { // already initialized at compile time @@ -31,13 +28,33 @@ impl Operation for DefVar { context.vm.environments.put_value_if_uninitialized( binding_locator.environment_index(), binding_locator.binding_index(), - JsValue::Undefined, + JsValue::undefined(), ); } Ok(CompletionType::Normal) } } +impl Operation for DefVar { + const NAME: &'static str = "DefVar"; + const INSTRUCTION: &'static str = "INST - DefVar"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} + /// `DefInitVar` implements the Opcode Operation for `Opcode::DefInitVar` /// /// Operation: @@ -45,14 +62,10 @@ impl Operation for DefVar { #[derive(Debug, Clone, Copy)] pub(crate) struct DefInitVar; -impl Operation for DefInitVar { - const NAME: &'static str = "DefInitVar"; - const INSTRUCTION: &'static str = "INST - DefInitVar"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl DefInitVar { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let value = context.vm.pop(); - let mut binding_locator = context.vm.frame().code_block.bindings[index as usize]; + let mut binding_locator = context.vm.frame().code_block.bindings[index]; context.find_runtime_binding(&mut binding_locator)?; @@ -66,6 +79,26 @@ impl Operation for DefInitVar { } } +impl Operation for DefInitVar { + const NAME: &'static str = "DefInitVar"; + const INSTRUCTION: &'static str = "INST - DefInitVar"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} + /// `PutLexicalValue` implements the Opcode Operation for `Opcode::PutLexicalValue` /// /// Operation: @@ -73,19 +106,37 @@ impl Operation for DefInitVar { #[derive(Debug, Clone, Copy)] pub(crate) struct PutLexicalValue; -impl Operation for PutLexicalValue { - const NAME: &'static str = "PutLexicalValue"; - const INSTRUCTION: &'static str = "INST - PutLexicalValue"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl PutLexicalValue { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let value = context.vm.pop(); - let binding_locator = context.vm.frame().code_block.bindings[index as usize]; + let binding_locator = context.vm.frame().code_block.bindings[index]; context.vm.environments.put_lexical_value( binding_locator.environment_index(), binding_locator.binding_index(), value, ); + Ok(CompletionType::Normal) } } + +impl Operation for PutLexicalValue { + const NAME: &'static str = "PutLexicalValue"; + const INSTRUCTION: &'static str = "INST - PutLexicalValue"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} diff --git a/boa_engine/src/vm/opcode/define/own_property.rs b/boa_engine/src/vm/opcode/define/own_property.rs index 30de98a2a48..91daaf92b40 100644 --- a/boa_engine/src/vm/opcode/define/own_property.rs +++ b/boa_engine/src/vm/opcode/define/own_property.rs @@ -11,12 +11,8 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct DefineOwnPropertyByName; -impl Operation for DefineOwnPropertyByName { - const NAME: &'static str = "DefineOwnPropertyByName"; - const INSTRUCTION: &'static str = "INST - DefineOwnPropertyByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl DefineOwnPropertyByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let value = context.vm.pop(); let object = context.vm.pop(); let object = if let Some(object) = object.as_object() { @@ -24,7 +20,7 @@ impl Operation for DefineOwnPropertyByName { } else { object.to_object(context)? }; - let name = context.vm.frame().code_block.names[index as usize].clone(); + let name = context.vm.frame().code_block.names[index].clone(); object.__define_own_property__( &name.into(), PropertyDescriptor::builder() @@ -39,6 +35,26 @@ impl Operation for DefineOwnPropertyByName { } } +impl Operation for DefineOwnPropertyByName { + const NAME: &'static str = "DefineOwnPropertyByName"; + const INSTRUCTION: &'static str = "INST - DefineOwnPropertyByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `DefineOwnPropertyByValue` implements the Opcode Operation for `Opcode::DefineOwnPropertyByValue` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/delete/mod.rs b/boa_engine/src/vm/opcode/delete/mod.rs index 22129fb35ba..ddeb0ec1d60 100644 --- a/boa_engine/src/vm/opcode/delete/mod.rs +++ b/boa_engine/src/vm/opcode/delete/mod.rs @@ -11,17 +11,11 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct DeletePropertyByName; -impl Operation for DeletePropertyByName { - const NAME: &'static str = "DeletePropertyByName"; - const INSTRUCTION: &'static str = "INST - DeletePropertyByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl DeletePropertyByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let value = context.vm.pop(); let object = value.to_object(context)?; - let key = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let key = context.vm.frame().code_block.names[index].clone().into(); let result = object.__delete__(&key, context)?; if !result && context.vm.frame().code_block.strict() { return Err(JsNativeError::typ() @@ -33,6 +27,26 @@ impl Operation for DeletePropertyByName { } } +impl Operation for DeletePropertyByName { + const NAME: &'static str = "DeletePropertyByName"; + const INSTRUCTION: &'static str = "INST - DeletePropertyByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `DeletePropertyByValue` implements the Opcode Operation for `Opcode::DeletePropertyByValue` /// /// Operation: @@ -67,13 +81,9 @@ impl Operation for DeletePropertyByValue { #[derive(Debug, Clone, Copy)] pub(crate) struct DeleteName; -impl Operation for DeleteName { - const NAME: &'static str = "DeleteName"; - const INSTRUCTION: &'static str = "INST - DeleteName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let mut binding_locator = context.vm.frame().code_block.bindings[index as usize]; +impl DeleteName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let mut binding_locator = context.vm.frame().code_block.bindings[index]; context.find_runtime_binding(&mut binding_locator)?; @@ -84,6 +94,26 @@ impl Operation for DeleteName { } } +impl Operation for DeleteName { + const NAME: &'static str = "DeleteName"; + const INSTRUCTION: &'static str = "INST - DeleteName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} + /// `DeleteSuperThrow` implements the Opcode Operation for `Opcode::DeleteSuperThrow` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/environment/mod.rs b/boa_engine/src/vm/opcode/environment/mod.rs index a0873ea91c2..bd04b9db40d 100644 --- a/boa_engine/src/vm/opcode/environment/mod.rs +++ b/boa_engine/src/vm/opcode/environment/mod.rs @@ -108,13 +108,9 @@ impl Operation for SuperCallPrepare { #[derive(Debug, Clone, Copy)] pub(crate) struct SuperCall; -impl Operation for SuperCall { - const NAME: &'static str = "SuperCall"; - const INSTRUCTION: &'static str = "INST - SuperCall"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let argument_count = context.vm.read::(); - let mut arguments = Vec::with_capacity(argument_count as usize); +impl SuperCall { + fn operation(context: &mut Context<'_>, argument_count: usize) -> JsResult { + let mut arguments = Vec::with_capacity(argument_count); for _ in 0..argument_count { arguments.push(context.vm.pop()); } @@ -152,6 +148,26 @@ impl Operation for SuperCall { } } +impl Operation for SuperCall { + const NAME: &'static str = "SuperCall"; + const INSTRUCTION: &'static str = "INST - SuperCall"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let value_count = context.vm.read::() as usize; + Self::operation(context, value_count) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let value_count = context.vm.read::() as usize; + Self::operation(context, value_count) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let value_count = context.vm.read::() as usize; + Self::operation(context, value_count) + } +} + /// `SuperCallSpread` implements the Opcode Operation for `Opcode::SuperCallSpread` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/get/function.rs b/boa_engine/src/vm/opcode/get/function.rs index dd32a0d04e3..0c403bbc1fe 100644 --- a/boa_engine/src/vm/opcode/get/function.rs +++ b/boa_engine/src/vm/opcode/get/function.rs @@ -10,17 +10,33 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct GetArrowFunction; +impl GetArrowFunction { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let code = context.vm.frame().code_block.functions[index].clone(); + let function = create_function_object_fast(code, false, true, false, context); + context.vm.push(function); + Ok(CompletionType::Normal) + } +} + impl Operation for GetArrowFunction { const NAME: &'static str = "GetArrowFunction"; const INSTRUCTION: &'static str = "INST - GetArrowFunction"; fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - context.vm.read::(); - let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_function_object_fast(code, false, true, false, context); - context.vm.push(function); - Ok(CompletionType::Normal) + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) } } @@ -31,17 +47,33 @@ impl Operation for GetArrowFunction { #[derive(Debug, Clone, Copy)] pub(crate) struct GetAsyncArrowFunction; +impl GetAsyncArrowFunction { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let code = context.vm.frame().code_block.functions[index].clone(); + let function = create_function_object_fast(code, true, true, false, context); + context.vm.push(function); + Ok(CompletionType::Normal) + } +} + impl Operation for GetAsyncArrowFunction { const NAME: &'static str = "GetAsyncArrowFunction"; const INSTRUCTION: &'static str = "INST - GetAsyncArrowFunction"; fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - context.vm.read::(); - let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_function_object_fast(code, true, true, false, context); - context.vm.push(function); - Ok(CompletionType::Normal) + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) } } @@ -52,17 +84,40 @@ impl Operation for GetAsyncArrowFunction { #[derive(Debug, Clone, Copy)] pub(crate) struct GetFunction; +impl GetFunction { + #[allow(clippy::unnecessary_wraps)] + fn operation( + context: &mut Context<'_>, + index: usize, + method: bool, + ) -> JsResult { + let code = context.vm.frame().code_block.functions[index].clone(); + let function = create_function_object_fast(code, false, false, method, context); + context.vm.push(function); + Ok(CompletionType::Normal) + } +} + impl Operation for GetFunction { const NAME: &'static str = "GetFunction"; const INSTRUCTION: &'static str = "INST - GetFunction"; fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); + let index = context.vm.read::() as usize; let method = context.vm.read::() != 0; - let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_function_object_fast(code, false, false, method, context); - context.vm.push(function); - Ok(CompletionType::Normal) + Self::operation(context, index, method) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + let method = context.vm.read::() != 0; + Self::operation(context, index, method) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + let method = context.vm.read::() != 0; + Self::operation(context, index, method) } } @@ -73,16 +128,39 @@ impl Operation for GetFunction { #[derive(Debug, Clone, Copy)] pub(crate) struct GetFunctionAsync; +impl GetFunctionAsync { + #[allow(clippy::unnecessary_wraps)] + fn operation( + context: &mut Context<'_>, + index: usize, + method: bool, + ) -> JsResult { + let code = context.vm.frame().code_block.functions[index].clone(); + let function = create_function_object_fast(code, true, false, method, context); + context.vm.push(function); + Ok(CompletionType::Normal) + } +} + impl Operation for GetFunctionAsync { const NAME: &'static str = "GetFunctionAsync"; const INSTRUCTION: &'static str = "INST - GetFunctionAsync"; fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); + let index = context.vm.read::() as usize; let method = context.vm.read::() != 0; - let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_function_object_fast(code, true, false, method, context); - context.vm.push(function); - Ok(CompletionType::Normal) + Self::operation(context, index, method) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + let method = context.vm.read::() != 0; + Self::operation(context, index, method) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + let method = context.vm.read::() != 0; + Self::operation(context, index, method) } } diff --git a/boa_engine/src/vm/opcode/get/generator.rs b/boa_engine/src/vm/opcode/get/generator.rs index 875b94b8200..83b99347d7a 100644 --- a/boa_engine/src/vm/opcode/get/generator.rs +++ b/boa_engine/src/vm/opcode/get/generator.rs @@ -10,16 +10,33 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct GetGenerator; +impl GetGenerator { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let code = context.vm.frame().code_block.functions[index].clone(); + let function = create_generator_function_object(code, false, None, context); + context.vm.push(function); + Ok(CompletionType::Normal) + } +} + impl Operation for GetGenerator { const NAME: &'static str = "GetGenerator"; const INSTRUCTION: &'static str = "INST - GetGenerator"; fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_generator_function_object(code, false, None, context); - context.vm.push(function); - Ok(CompletionType::Normal) + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) } } @@ -30,15 +47,32 @@ impl Operation for GetGenerator { #[derive(Debug, Clone, Copy)] pub(crate) struct GetGeneratorAsync; +impl GetGeneratorAsync { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let code = context.vm.frame().code_block.functions[index].clone(); + let function = create_generator_function_object(code, true, None, context); + context.vm.push(function); + Ok(CompletionType::Normal) + } +} + impl Operation for GetGeneratorAsync { const NAME: &'static str = "GetGeneratorAsync"; const INSTRUCTION: &'static str = "INST - GetGeneratorAsync"; fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_generator_function_object(code, true, None, context); - context.vm.push(function); - Ok(CompletionType::Normal) + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) } } diff --git a/boa_engine/src/vm/opcode/get/name.rs b/boa_engine/src/vm/opcode/get/name.rs index 3a067b370fd..31812939706 100644 --- a/boa_engine/src/vm/opcode/get/name.rs +++ b/boa_engine/src/vm/opcode/get/name.rs @@ -11,13 +11,9 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct GetName; -impl Operation for GetName { - const NAME: &'static str = "GetName"; - const INSTRUCTION: &'static str = "INST - GetName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let mut binding_locator = context.vm.frame().code_block.bindings[index as usize]; +impl GetName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let mut binding_locator = context.vm.frame().code_block.bindings[index]; context.find_runtime_binding(&mut binding_locator)?; let value = context.get_binding(binding_locator)?.ok_or_else(|| { let name = context @@ -32,6 +28,26 @@ impl Operation for GetName { } } +impl Operation for GetName { + const NAME: &'static str = "GetName"; + const INSTRUCTION: &'static str = "INST - GetName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} + /// `GetLocator` implements the Opcode Operation for `Opcode::GetLocator` /// /// Operation: @@ -39,18 +55,34 @@ impl Operation for GetName { #[derive(Debug, Clone, Copy)] pub(crate) struct GetLocator; +impl GetLocator { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let mut binding_locator = context.vm.frame().code_block.bindings[index]; + context.find_runtime_binding(&mut binding_locator)?; + + context.vm.frame_mut().binding_stack.push(binding_locator); + + Ok(CompletionType::Normal) + } +} + impl Operation for GetLocator { const NAME: &'static str = "GetLocator"; const INSTRUCTION: &'static str = "INST - GetLocator"; fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let mut binding_locator = context.vm.frame().code_block.bindings[index as usize]; - context.find_runtime_binding(&mut binding_locator)?; + let index = context.vm.read::(); + Self::operation(context, index as usize) + } - context.vm.frame_mut().binding_stack.push(binding_locator); + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } - Ok(CompletionType::Normal) + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) } } @@ -62,13 +94,9 @@ impl Operation for GetLocator { #[derive(Debug, Clone, Copy)] pub(crate) struct GetNameAndLocator; -impl Operation for GetNameAndLocator { - const NAME: &'static str = "GetNameAndLocator"; - const INSTRUCTION: &'static str = "INST - GetNameAndLocator"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let mut binding_locator = context.vm.frame().code_block.bindings[index as usize]; +impl GetNameAndLocator { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let mut binding_locator = context.vm.frame().code_block.bindings[index]; context.find_runtime_binding(&mut binding_locator)?; let value = context.get_binding(binding_locator)?.ok_or_else(|| { let name = context @@ -84,6 +112,26 @@ impl Operation for GetNameAndLocator { } } +impl Operation for GetNameAndLocator { + const NAME: &'static str = "GetNameAndLocator"; + const INSTRUCTION: &'static str = "INST - GetNameAndLocator"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} + /// `GetNameOrUndefined` implements the Opcode Operation for `Opcode::GetNameOrUndefined` /// /// Operation: @@ -91,13 +139,9 @@ impl Operation for GetNameAndLocator { #[derive(Debug, Clone, Copy)] pub(crate) struct GetNameOrUndefined; -impl Operation for GetNameOrUndefined { - const NAME: &'static str = "GetNameOrUndefined"; - const INSTRUCTION: &'static str = "INST - GetNameOrUndefined"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let mut binding_locator = context.vm.frame().code_block.bindings[index as usize]; +impl GetNameOrUndefined { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let mut binding_locator = context.vm.frame().code_block.bindings[index]; let is_global = binding_locator.is_global(); @@ -121,3 +165,23 @@ impl Operation for GetNameOrUndefined { Ok(CompletionType::Normal) } } + +impl Operation for GetNameOrUndefined { + const NAME: &'static str = "GetNameOrUndefined"; + const INSTRUCTION: &'static str = "INST - GetNameOrUndefined"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} diff --git a/boa_engine/src/vm/opcode/get/private.rs b/boa_engine/src/vm/opcode/get/private.rs index 2d6b1139ca1..1ba7518d386 100644 --- a/boa_engine/src/vm/opcode/get/private.rs +++ b/boa_engine/src/vm/opcode/get/private.rs @@ -10,13 +10,9 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct GetPrivateField; -impl Operation for GetPrivateField { - const NAME: &'static str = "GetPrivateField"; - const INSTRUCTION: &'static str = "INST - GetPrivateField"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl GetPrivateField { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let value = context.vm.pop(); let base_obj = value.to_object(context)?; @@ -31,3 +27,23 @@ impl Operation for GetPrivateField { Ok(CompletionType::Normal) } } + +impl Operation for GetPrivateField { + const NAME: &'static str = "GetPrivateField"; + const INSTRUCTION: &'static str = "INST - GetPrivateField"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} diff --git a/boa_engine/src/vm/opcode/get/property.rs b/boa_engine/src/vm/opcode/get/property.rs index 5028b343cfb..c3ba937e03c 100644 --- a/boa_engine/src/vm/opcode/get/property.rs +++ b/boa_engine/src/vm/opcode/get/property.rs @@ -1,7 +1,7 @@ use crate::{ property::PropertyKey, vm::{opcode::Operation, CompletionType}, - Context, JsResult, JsValue, + Context, JsResult, }; /// `GetPropertyByName` implements the Opcode Operation for `Opcode::GetPropertyByName` @@ -11,13 +11,8 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct GetPropertyByName; -impl Operation for GetPropertyByName { - const NAME: &'static str = "GetPropertyByName"; - const INSTRUCTION: &'static str = "INST - GetPropertyByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - +impl GetPropertyByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let receiver = context.vm.pop(); let value = context.vm.pop(); let object = if let Some(object) = value.as_object() { @@ -26,9 +21,7 @@ impl Operation for GetPropertyByName { value.to_object(context)? }; - let key = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let key = context.vm.frame().code_block.names[index].clone().into(); let result = object.__get__(&key, receiver, context)?; context.vm.push(result); @@ -36,6 +29,26 @@ impl Operation for GetPropertyByName { } } +impl Operation for GetPropertyByName { + const NAME: &'static str = "GetPropertyByName"; + const INSTRUCTION: &'static str = "INST - GetPropertyByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} + /// `GetPropertyByValue` implements the Opcode Operation for `Opcode::GetPropertyByValue` /// /// Operation: @@ -82,31 +95,6 @@ impl Operation for GetPropertyByValue { } } -/// `GetMethod` implements the Opcode Operation for `Opcode::GetMethod` -/// -/// Operation: -/// - Get a property method or undefined if the property is null or undefined. -#[derive(Debug, Clone, Copy)] -pub(crate) struct GetMethod; - -impl Operation for GetMethod { - const NAME: &'static str = "GetMethod"; - const INSTRUCTION: &'static str = "INST - GetMethod"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let key = context.vm.frame().code_block.names[index as usize].clone(); - let value = context.vm.pop(); - - let method = value.get_method(key, context)?; - context.vm.push(value); - context - .vm - .push(method.map(JsValue::from).unwrap_or_default()); - Ok(CompletionType::Normal) - } -} - /// `GetPropertyByValuePush` implements the Opcode Operation for `Opcode::GetPropertyByValuePush` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index 177e1d20d2a..04563ddcc8f 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -18,6 +18,7 @@ mod generator; mod get; mod iteration; mod meta; +mod modifier; mod new; mod nop; mod pop; @@ -60,6 +61,8 @@ pub(crate) use iteration::*; #[doc(inline)] pub(crate) use meta::*; #[doc(inline)] +pub(crate) use modifier::*; +#[doc(inline)] pub(crate) use new::*; #[doc(inline)] pub(crate) use nop::*; @@ -121,16 +124,86 @@ where unsafe { read_unchecked(bytes, offset) } } +/// Represents a varying operand kind. +#[derive(Default, Debug, Clone, Copy)] +pub(crate) enum VaryingOperandKind { + #[default] + U8, + U16, + U32, +} + +#[derive(Debug, Clone, Copy)] +pub(crate) struct VaryingOperand { + kind: VaryingOperandKind, + value: u32, +} + +impl PartialEq for VaryingOperand { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + } +} + +impl VaryingOperand { + #[must_use] + pub(crate) fn u8(value: u8) -> Self { + Self { + kind: VaryingOperandKind::U8, + value: u32::from(value), + } + } + #[must_use] + pub(crate) fn u16(value: u16) -> Self { + Self { + kind: VaryingOperandKind::U16, + value: u32::from(value), + } + } + #[must_use] + pub(crate) const fn u32(value: u32) -> Self { + Self { + kind: VaryingOperandKind::U32, + value, + } + } + #[must_use] + pub(crate) const fn value(self) -> u32 { + self.value + } + #[must_use] + pub(crate) const fn kind(self) -> VaryingOperandKind { + self.kind + } +} + trait BytecodeConversion: Sized { fn to_bytecode(&self, bytes: &mut Vec); - 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) { + match self.kind() { + VaryingOperandKind::U8 => u8::to_bytecode(&(self.value() as u8), bytes), + VaryingOperandKind::U16 => u16::to_bytecode(&(self.value() as u16), bytes), + VaryingOperandKind::U32 => u32::to_bytecode(&self.value(), bytes), + } + } + fn from_bytecode(bytes: &[u8], pc: &mut usize, varying_kind: VaryingOperandKind) -> Self { + match varying_kind { + VaryingOperandKind::U8 => Self::u8(u8::from_bytecode(bytes, pc, varying_kind)), + VaryingOperandKind::U16 => Self::u16(u16::from_bytecode(bytes, pc, varying_kind)), + VaryingOperandKind::U32 => Self::u32(u32::from_bytecode(bytes, pc, varying_kind)), + } + } } impl BytecodeConversion for GeneratorResumeKind { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); JsValue::from(value).to_generator_resume_kind() @@ -141,7 +214,7 @@ impl BytecodeConversion for bool { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value != 0 @@ -152,7 +225,7 @@ impl BytecodeConversion for i8 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -163,7 +236,7 @@ impl BytecodeConversion for u8 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -174,7 +247,7 @@ impl BytecodeConversion for i16 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -185,7 +258,7 @@ impl BytecodeConversion for u16 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -196,7 +269,7 @@ impl BytecodeConversion for i32 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -207,7 +280,7 @@ impl BytecodeConversion for u32 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -218,7 +291,7 @@ impl BytecodeConversion for i64 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -229,7 +302,7 @@ impl BytecodeConversion for u64 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -240,7 +313,7 @@ impl BytecodeConversion for f32 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -251,7 +324,7 @@ impl BytecodeConversion for f64 { fn to_bytecode(&self, bytes: &mut Vec) { 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::(bytes, *pc); *pc += std::mem::size_of::(); value @@ -265,7 +338,7 @@ impl BytecodeConversion for ThinVec { 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::(bytes, *pc); *pc += std::mem::size_of::(); let mut result = Self::with_capacity(count as usize); @@ -302,7 +375,7 @@ macro_rules! generate_opcodes { /// The opcodes of the vm. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] - pub enum Opcode { + pub(crate) enum Opcode { $( $(#[$inner $($args)*])* $Variant @@ -323,30 +396,36 @@ macro_rules! generate_opcodes { } impl Opcode { - const MAX: usize = 2usize.pow(8); + const MAX: usize = 2usize.pow(8) * 3; const NAMES: [&'static str; Self::MAX] = [ + $( $mapping)?)>::NAME),*, + $( $mapping)?)>::NAME),*, $( $mapping)?)>::NAME),* ]; /// Name of this opcode. #[must_use] - pub const fn as_str(self) -> &'static str { + pub(crate) const fn as_str(self) -> &'static str { Self::NAMES[self as usize] } const INSTRUCTIONS: [&'static str; Self::MAX] = [ + $( $mapping)?)>::INSTRUCTION),*, + $( $mapping)?)>::INSTRUCTION),*, $( $mapping)?)>::INSTRUCTION),* ]; /// Name of the profiler event for this opcode. #[must_use] - pub const fn as_instruction_str(self) -> &'static str { + pub(crate) const fn as_instruction_str(self) -> &'static str { Self::INSTRUCTIONS[self as usize] } const EXECUTE_FNS: [fn(&mut Context<'_>) -> JsResult; Self::MAX] = [ - $( $mapping)?)>::execute),* + $( $mapping)?)>::execute),*, + $( $mapping)?)>::execute_with_u16_operands),*, + $( $mapping)?)>::execute_with_u32_operands),* ]; pub(super) fn execute(self, context: &mut Context<'_>) -> JsResult { @@ -355,15 +434,18 @@ macro_rules! generate_opcodes { } /// This represents a VM instruction, it contains both opcode and operands. + /// + // TODO: An instruction should be a representation of a valid executable instruction (opcode + operands), + // so variants like `ResevedN`, or operand width prefix modifiers, idealy shouldn't + // be a part of `Instruction`. #[derive(Debug, Clone, PartialEq)] #[repr(u8)] - pub enum Instruction { + pub(crate) enum Instruction { $( $(#[$inner $($args)*])* $Variant $({ $( $(#[$fieldinner $($fieldargs)*])* - #[allow(missing_docs)] $FieldName : $FieldType ),* })? @@ -373,7 +455,8 @@ macro_rules! generate_opcodes { impl Instruction { /// Convert [`Instruction`] to compact bytecode. #[inline] - pub fn to_bytecode(&self, bytes: &mut Vec) { + #[allow(dead_code)] + pub(crate) fn to_bytecode(&self, bytes: &mut Vec) { match self { $( Self::$Variant $({ @@ -395,7 +478,7 @@ macro_rules! generate_opcodes { /// If the provided bytecode is not valid. #[inline] #[must_use] - pub fn from_bytecode(bytes: &[u8], pc: &mut usize) -> Self { + pub(crate) fn from_bytecode(bytes: &[u8], pc: &mut usize, varying_kind: VaryingOperandKind) -> Self { let opcode = bytes[*pc].into(); *pc += 1; match opcode { @@ -406,7 +489,7 @@ macro_rules! generate_opcodes { $({ Self::$Variant { $( - $FieldName: BytecodeConversion::from_bytecode(bytes, pc) + $FieldName: BytecodeConversion::from_bytecode(bytes, pc, varying_kind) ),* } })? @@ -422,7 +505,7 @@ macro_rules! generate_opcodes { /// Get the [`Opcode`] of the [`Instruction`]. #[inline] #[must_use] - pub const fn opcode(&self) -> Opcode { + pub(crate) const fn opcode(&self) -> Opcode { match self { $( Self::$Variant $({ $( $FieldName: _ ),* })? => Opcode::$Variant @@ -442,7 +525,22 @@ pub(crate) trait Operation { const NAME: &'static str; const INSTRUCTION: &'static str; + /// Execute opcode with [`VaryingOperandKind::U8`] sized [`VaryingOperand`]s. fn execute(context: &mut Context<'_>) -> JsResult; + + /// 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 { + 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 { + Reserved::execute_with_u32_operands(context) + } } generate_opcodes! { @@ -593,7 +691,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: **=>** (`literals[index]`) - PushLiteral { index: u32 }, + PushLiteral { index: VaryingOperand }, /// Push empty object `{}` value on the stack. /// @@ -770,7 +868,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: rhs **=>** (private_name `in` rhs) - InPrivate { index: u32 }, + InPrivate { index: VaryingOperand }, /// Binary `==` operator. /// @@ -931,42 +1029,42 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: **=>** - DefVar { index: u32 }, + DefVar { index: VaryingOperand }, /// Declare and initialize `var` type variable. /// /// Operands: index: `u32` /// /// Stack: value **=>** - DefInitVar { index: u32 }, + DefInitVar { index: VaryingOperand }, /// Initialize a lexical binding. /// /// Operands: index: `u32` /// /// Stack: value **=>** - PutLexicalValue { index: u32 }, + PutLexicalValue { index: VaryingOperand }, /// Throws an error because the binding access is illegal. /// /// Operands: index: `u32` /// /// Stack: **=>** - ThrowMutateImmutable { index: u32 }, + ThrowMutateImmutable { index: VaryingOperand }, /// Find a binding on the environment chain and push its value. /// /// Operands: index: `u32` /// /// Stack: **=>** value - GetName { index: u32 }, + GetName { index: VaryingOperand }, /// Find a binding on the environment and set the `current_binding` of the current frame. /// /// Operands: index: `u32` /// /// Stack: **=>** - GetLocator { index: u32 }, + GetLocator { index: VaryingOperand }, /// Find a binding on the environment chain and push its value to the stack and its /// `BindingLocator` to the `bindings_stack`. @@ -974,21 +1072,21 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: **=>** value - GetNameAndLocator { index: u32 }, + GetNameAndLocator { index: VaryingOperand }, /// Find a binding on the environment chain and push its value. If the binding does not exist push undefined. /// /// Operands: index: `u32` /// /// Stack: **=>** value - GetNameOrUndefined { index: u32 }, + GetNameOrUndefined { index: VaryingOperand }, /// Find a binding on the environment chain and assign its value. /// /// Operands: index: `u32` /// /// Stack: value **=>** - SetName { index: u32 }, + SetName { index: VaryingOperand }, /// Assigns a value to the binding pointed by the top of the `bindings_stack`. /// @@ -1000,7 +1098,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: **=>** deleted - DeleteName { index: u32 }, + DeleteName { index: VaryingOperand }, /// Get a property by name from an object an push it on the stack. /// @@ -1009,15 +1107,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, receiver **=>** value - GetPropertyByName { index: u32 }, - - /// Get a property method or undefined if the property is null or undefined. - /// - /// Throws if the method is not a callable object. - /// - /// Operands: index: `u32` - /// Stack: object **=>** object, method - GetMethod { index: u32 }, + GetPropertyByName { index: VaryingOperand }, /// Get a property by value from an object an push it on the stack. /// @@ -1044,7 +1134,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, receiver, value **=>** value - SetPropertyByName { index: u32 }, + SetPropertyByName { index: VaryingOperand }, /// Sets the name of a function object. /// @@ -1067,21 +1157,21 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, value **=>** - DefineOwnPropertyByName { index: u32 }, + DefineOwnPropertyByName { index: VaryingOperand }, /// Defines a static class method by name. /// /// Operands: index: `u32` /// /// Stack: class, function **=>** - DefineClassStaticMethodByName { index: u32 }, + DefineClassStaticMethodByName { index: VaryingOperand }, /// Defines a class method by name. /// /// Operands: index: `u32` /// /// Stack: class_proto, function **=>** - DefineClassMethodByName { index: u32 }, + DefineClassMethodByName { index: VaryingOperand }, /// Sets a property by value of an object. /// @@ -1120,7 +1210,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, value **=>** - SetPropertyGetterByName { index: u32 }, + SetPropertyGetterByName { index: VaryingOperand }, /// Defines a static getter class method by name. /// @@ -1129,7 +1219,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: class, binding_function **=>** - DefineClassStaticGetterByName { index: u32 }, + DefineClassStaticGetterByName { index: VaryingOperand }, /// Defines a getter class method by name. /// @@ -1138,7 +1228,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: class_proto, function **=>** class - DefineClassGetterByName { index: u32 }, + DefineClassGetterByName { index: VaryingOperand }, /// Sets a getter property by value of an object. /// @@ -1174,7 +1264,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, value **=>** - SetPropertySetterByName { index: u32 }, + SetPropertySetterByName { index: VaryingOperand }, /// Defines a static setter class method by name. /// @@ -1183,7 +1273,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: class, function **=>** - DefineClassStaticSetterByName { index: u32 }, + DefineClassStaticSetterByName { index: VaryingOperand }, /// Defines a setter class method by name. /// @@ -1192,7 +1282,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: class_proto, function **=>** - DefineClassSetterByName { index: u32 }, + DefineClassSetterByName { index: VaryingOperand }, /// Sets a setter property by value of an object. /// @@ -1228,7 +1318,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, value **=>** value - SetPrivateField { index: u32 }, + SetPrivateField { index: VaryingOperand }, /// Define a private property of a class constructor by it's name. /// @@ -1237,7 +1327,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, value **=>** - DefinePrivateField { index: u32 }, + DefinePrivateField { index: VaryingOperand }, /// Set a private method of a class constructor by it's name. /// @@ -1246,7 +1336,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, value **=>** - SetPrivateMethod { index: u32 }, + SetPrivateMethod { index: VaryingOperand }, /// Set a private setter property of a class constructor by it's name. /// @@ -1255,7 +1345,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, value **=>** - SetPrivateSetter { index: u32 }, + SetPrivateSetter { index: VaryingOperand }, /// Set a private getter property of a class constructor by it's name. /// @@ -1264,7 +1354,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object, value **=>** - SetPrivateGetter { index: u32 }, + SetPrivateGetter { index: VaryingOperand }, /// Get a private property by name from an object an push it on the stack. /// @@ -1273,7 +1363,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object **=>** value - GetPrivateField { index: u32 }, + GetPrivateField { index: VaryingOperand }, /// Push a field to a class. /// @@ -1287,28 +1377,28 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: class, field_function **=>** - PushClassFieldPrivate { index: u32 }, + PushClassFieldPrivate { index: VaryingOperand }, /// Push a private getter to the class. /// /// Operands: index: `u32` /// /// Stack: class, getter **=>** - PushClassPrivateGetter { index: u32 }, + PushClassPrivateGetter { index: VaryingOperand }, /// Push a private setter to the class. /// /// Operands: index: `u32` /// /// Stack: class, setter **=>** - PushClassPrivateSetter { index: u32 }, + PushClassPrivateSetter { index: VaryingOperand }, /// Push a private method to the class. /// /// Operands: index: `u32` /// /// Stack: class, method **=>** - PushClassPrivateMethod { index: u32 }, + PushClassPrivateMethod { index: VaryingOperand }, /// Deletes a property by name of an object. /// @@ -1317,7 +1407,7 @@ generate_opcodes! { /// Operands: index: `u32` /// /// Stack: object **=>** - DeletePropertyByName { index: u32 }, + DeletePropertyByName { index: VaryingOperand }, /// Deletes a property by value of an object. /// @@ -1337,10 +1427,10 @@ generate_opcodes! { /// Copy all properties of one object to another object. /// - /// Operands: excluded_key_count: `u32`, excluded_key_count_computed: `u32` + /// Operands: excluded_key_count: `VaryingOperand`, excluded_key_count_computed: `VaryingOperand` /// /// Stack: excluded_key_computed_0 ... excluded_key_computed_n, source, value, excluded_key_0 ... excluded_key_n **=>** value - CopyDataProperties { excluded_key_count: u32, excluded_key_count_computed: u32 }, + CopyDataProperties { excluded_key_count: VaryingOperand, excluded_key_count_computed: VaryingOperand }, /// Call ToPropertyKey on the value on the stack. /// @@ -1448,7 +1538,7 @@ generate_opcodes! { /// Operands: message: u32 /// /// Stack: **=>** - ThrowNewTypeError { message: u32 }, + ThrowNewTypeError { message: VaryingOperand }, /// Pops value converts it to boolean and pushes it back. /// @@ -1483,7 +1573,7 @@ generate_opcodes! { /// Operands: argument_count: `u32` /// /// Stack: super_constructor, new_target, argument_1, ... argument_n **=>** - SuperCall { argument_count: u32 }, + SuperCall { argument_count: VaryingOperand }, /// Execute the `super()` method where the arguments contain spreads. /// @@ -1523,52 +1613,52 @@ generate_opcodes! { /// Get arrow function from the pre-compiled inner functions. /// - /// Operands: address: `u32`, method: `u8` + /// Operands: index: `u32` /// /// Stack: **=>** func - GetArrowFunction { index: u32, method: bool }, + GetArrowFunction { index: VaryingOperand }, /// Get async arrow function from the pre-compiled inner functions. /// - /// Operands: index: `u32`, method: `u8` + /// Operands: index: `VaryingOperand` /// /// Stack: **=>** func - GetAsyncArrowFunction { index: u32, method: bool }, + GetAsyncArrowFunction { index: VaryingOperand }, /// Get function from the pre-compiled inner functions. /// - /// Operands: index: `u32`, is_method: `u8` + /// Operands: index: `VaryingOperand`, is_method: `u8` /// /// Stack: **=>** func - GetFunction { index: u32, method: bool }, + GetFunction { index: VaryingOperand, method: bool }, /// Get async function from the pre-compiled inner functions. /// - /// Operands: index: `u32`, method: `u8` + /// Operands: index: `VaryingOperand`, method: `u8` /// /// Stack: **=>** func - GetFunctionAsync { index: u32, method: bool }, + GetFunctionAsync { index: VaryingOperand, method: bool }, /// Get generator function from the pre-compiled inner functions. /// - /// Operands: index: `u32`, + /// Operands: index: `VaryingOperand`, /// /// Stack: **=>** func - GetGenerator { index: u32 }, + GetGenerator { index: VaryingOperand }, /// Get async generator function from the pre-compiled inner functions. /// - /// Operands: index: `u32`, + /// Operands: index: `VaryingOperand`, /// /// Stack: **=>** func - GetGeneratorAsync { index: u32 }, + GetGeneratorAsync { index: VaryingOperand }, /// Call a function named "eval". /// - /// Operands: argument_count: `u32` + /// Operands: argument_count: `VaryingOperand` /// /// Stack: this, func, argument_1, ... argument_n **=>** result - CallEval { argument_count: u32 }, + CallEval { argument_count: VaryingOperand }, /// Call a function named "eval" where the arguments contain spreads. /// @@ -1582,7 +1672,7 @@ generate_opcodes! { /// Operands: argument_count: `u32` /// /// Stack: this, func, argument_1, ... argument_n **=>** result - Call { argument_count: u32 }, + Call { argument_count: VaryingOperand }, /// Call a function where the arguments contain spreads. /// @@ -1596,7 +1686,7 @@ generate_opcodes! { /// Operands: argument_count: `u32` /// /// Stack: func, argument_1, ... argument_n **=>** result - New { argument_count: u32 }, + New { argument_count: VaryingOperand }, /// Call construct on a function where the arguments contain spreads. /// @@ -1800,7 +1890,7 @@ generate_opcodes! { /// Operands: value_count: `u32` /// /// Stack: `value_1`,...`value_n` **=>** `string` - ConcatToString { value_count: u32 }, + ConcatToString { value_count: VaryingOperand }, /// Call RequireObjectCoercible on the stack value. /// @@ -1928,10 +2018,10 @@ generate_opcodes! { /// Create a new tagged template object and cache it. /// - /// Operands: count: `u32`, site: `u64` + /// Operands: count: `VaryingOperand`, site: `u64` /// /// Stack: count * (cooked_value, raw_value) **=>** template - TemplateCreate { count: u32, site: u64 }, + TemplateCreate { count: VaryingOperand, site: u64 }, /// Push a private environment. /// @@ -1954,6 +2044,20 @@ generate_opcodes! { /// Stack: **=>** Nop, + /// Opcode prefix modifier, makes all [`VaryingOperand`]s of an instruction [`u16`] sized. + /// + /// Operands: opcode (operands if any). + /// + /// Stack: The stack changes based on the opcode that is being prefixed. + U16Operands, + + /// Opcode prefix modifier, [`Opcode`] prefix operand modifier, makes all [`VaryingOperand`]s of an instruction [`u32`] sized. + /// + /// Operands: opcode (operands if any). + /// + /// Stack: The stack changes based on the opcode that is being prefixed. + U32Operands, + /// Reserved [`Opcode`]. Reserved1 => Reserved, /// Reserved [`Opcode`]. @@ -2068,8 +2172,6 @@ generate_opcodes! { Reserved56 => Reserved, /// Reserved [`Opcode`]. Reserved57 => Reserved, - /// Reserved [`Opcode`]. - Reserved58 => Reserved, } /// Specific opcodes for bindings. @@ -2086,7 +2188,7 @@ pub(crate) enum BindingOpcode { /// Iterator over the instructions in the compact bytecode. #[derive(Debug, Clone)] -pub struct InstructionIterator<'bytecode> { +pub(crate) struct InstructionIterator<'bytecode> { bytes: &'bytecode [u8], pc: usize, } @@ -2095,21 +2197,52 @@ impl<'bytecode> InstructionIterator<'bytecode> { /// Create a new [`InstructionIterator`] from bytecode array. #[inline] #[must_use] - pub const fn new(bytes: &'bytecode [u8]) -> Self { + pub(crate) const fn new(bytes: &'bytecode [u8]) -> Self { Self { bytes, pc: 0 } } + + /// Create a new [`InstructionIterator`] from bytecode array at pc. + #[inline] + #[must_use] + pub(crate) const fn with_pc(bytes: &'bytecode [u8], pc: usize) -> Self { + Self { bytes, pc } + } + + /// Return the current program counter. + #[must_use] + pub(crate) const fn pc(&self) -> usize { + self.pc + } } impl Iterator for InstructionIterator<'_> { - type Item = Instruction; + type Item = (usize, VaryingOperandKind, Instruction); #[inline] fn next(&mut self) -> Option { + let start_pc = self.pc; if self.pc >= self.bytes.len() { return None; } - Some(Instruction::from_bytecode(self.bytes, &mut self.pc)) + let instruction = + Instruction::from_bytecode(self.bytes, &mut self.pc, VaryingOperandKind::U8); + + if instruction == Instruction::U16Operands { + return Some(( + start_pc, + VaryingOperandKind::U16, + Instruction::from_bytecode(self.bytes, &mut self.pc, VaryingOperandKind::U16), + )); + } else if instruction == Instruction::U32Operands { + return Some(( + start_pc, + VaryingOperandKind::U32, + Instruction::from_bytecode(self.bytes, &mut self.pc, VaryingOperandKind::U32), + )); + } + + Some((start_pc, VaryingOperandKind::U8, instruction)) } } diff --git a/boa_engine/src/vm/opcode/modifier.rs b/boa_engine/src/vm/opcode/modifier.rs new file mode 100644 index 00000000000..96999ea40cd --- /dev/null +++ b/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 { + let opcode = context.vm.read::() 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 { + let opcode = context.vm.read::() as usize; + + Opcode::EXECUTE_FNS[256 * 2 + opcode](context) + } +} diff --git a/boa_engine/src/vm/opcode/new/mod.rs b/boa_engine/src/vm/opcode/new/mod.rs index 8e6c78a69a4..cf68063f35f 100644 --- a/boa_engine/src/vm/opcode/new/mod.rs +++ b/boa_engine/src/vm/opcode/new/mod.rs @@ -11,11 +11,8 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct New; -impl Operation for New { - const NAME: &'static str = "New"; - const INSTRUCTION: &'static str = "INST - New"; - - fn execute(context: &mut Context<'_>) -> JsResult { +impl New { + fn operation(context: &mut Context<'_>, argument_count: usize) -> JsResult { if context.vm.runtime_limits.recursion_limit() <= context.vm.frames.len() { return Err(JsNativeError::runtime_limit() .with_message(format!( @@ -29,8 +26,7 @@ impl Operation for New { .with_message("Maximum call stack size exceeded") .into()); } - let argument_count = context.vm.read::(); - let mut arguments = Vec::with_capacity(argument_count as usize); + let mut arguments = Vec::with_capacity(argument_count); for _ in 0..argument_count { arguments.push(context.vm.pop()); } @@ -51,6 +47,26 @@ impl Operation for New { } } +impl Operation for New { + const NAME: &'static str = "New"; + const INSTRUCTION: &'static str = "INST - New"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let argument_count = context.vm.read::() as usize; + Self::operation(context, argument_count) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let argument_count = context.vm.read::() as usize; + Self::operation(context, argument_count) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let argument_count = context.vm.read::() as usize; + Self::operation(context, argument_count) + } +} + /// `NewSpread` implements the Opcode Operation for `Opcode::NewSpread` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/nop/mod.rs b/boa_engine/src/vm/opcode/nop/mod.rs index 881902b9b70..8fd95297256 100644 --- a/boa_engine/src/vm/opcode/nop/mod.rs +++ b/boa_engine/src/vm/opcode/nop/mod.rs @@ -33,4 +33,12 @@ impl Operation for Reserved { fn execute(_: &mut Context<'_>) -> JsResult { unreachable!("Reserved opcodes are unreachable!") } + + fn execute_with_u16_operands(_: &mut Context<'_>) -> JsResult { + unreachable!("Reserved.U16 opcodes are unreachable!") + } + + fn execute_with_u32_operands(_: &mut Context<'_>) -> JsResult { + unreachable!("Reserved.U32 opcodes are unreachable!") + } } diff --git a/boa_engine/src/vm/opcode/push/class/field.rs b/boa_engine/src/vm/opcode/push/class/field.rs index f48bfbfecec..99b73d398d0 100644 --- a/boa_engine/src/vm/opcode/push/class/field.rs +++ b/boa_engine/src/vm/opcode/push/class/field.rs @@ -52,13 +52,10 @@ impl Operation for PushClassField { #[derive(Debug, Clone, Copy)] pub(crate) struct PushClassFieldPrivate; -impl Operation for PushClassFieldPrivate { - const NAME: &'static str = "PushClassFieldPrivate"; - const INSTRUCTION: &'static str = "INST - PushClassFieldPrivate"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl PushClassFieldPrivate { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let field_function_value = context.vm.pop(); let class_value = context.vm.pop(); @@ -86,3 +83,23 @@ impl Operation for PushClassFieldPrivate { Ok(CompletionType::Normal) } } + +impl Operation for PushClassFieldPrivate { + const NAME: &'static str = "PushClassFieldPrivate"; + const INSTRUCTION: &'static str = "INST - PushClassFieldPrivate"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} diff --git a/boa_engine/src/vm/opcode/push/class/private.rs b/boa_engine/src/vm/opcode/push/class/private.rs index e18ca0d2eed..15e26fcbf89 100644 --- a/boa_engine/src/vm/opcode/push/class/private.rs +++ b/boa_engine/src/vm/opcode/push/class/private.rs @@ -14,13 +14,10 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct PushClassPrivateMethod; -impl Operation for PushClassPrivateMethod { - const NAME: &'static str = "PushClassPrivateMethod"; - const INSTRUCTION: &'static str = "INST - PushClassPrivateMethod"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl PushClassPrivateMethod { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let method = context.vm.pop(); let method_object = method.as_callable().expect("method must be callable"); @@ -56,6 +53,26 @@ impl Operation for PushClassPrivateMethod { } } +impl Operation for PushClassPrivateMethod { + const NAME: &'static str = "PushClassPrivateMethod"; + const INSTRUCTION: &'static str = "INST - PushClassPrivateMethod"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `PushClassPrivateGetter` implements the Opcode Operation for `Opcode::PushClassPrivateGetter` /// /// Operation: @@ -63,13 +80,10 @@ impl Operation for PushClassPrivateMethod { #[derive(Debug, Clone, Copy)] pub(crate) struct PushClassPrivateGetter; -impl Operation for PushClassPrivateGetter { - const NAME: &'static str = "PushClassPrivateGetter"; - const INSTRUCTION: &'static str = "INST - PushClassPrivateGetter"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl PushClassPrivateGetter { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let getter = context.vm.pop(); let getter_object = getter.as_callable().expect("getter must be callable"); let class = context.vm.pop(); @@ -95,6 +109,26 @@ impl Operation for PushClassPrivateGetter { } } +impl Operation for PushClassPrivateGetter { + const NAME: &'static str = "PushClassPrivateGetter"; + const INSTRUCTION: &'static str = "INST - PushClassPrivateGetter"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `PushClassPrivateSetter` implements the Opcode Operation for `Opcode::PushClassPrivateSetter` /// /// Operation: @@ -102,13 +136,10 @@ impl Operation for PushClassPrivateGetter { #[derive(Debug, Clone, Copy)] pub(crate) struct PushClassPrivateSetter; -impl Operation for PushClassPrivateSetter { - const NAME: &'static str = "PushClassPrivateSetter"; - const INSTRUCTION: &'static str = "INST - PushClassPrivateSetter"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl PushClassPrivateSetter { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let setter = context.vm.pop(); let setter_object = setter.as_callable().expect("getter must be callable"); let class = context.vm.pop(); @@ -133,3 +164,23 @@ impl Operation for PushClassPrivateSetter { Ok(CompletionType::Normal) } } + +impl Operation for PushClassPrivateSetter { + const NAME: &'static str = "PushClassPrivateSetter"; + const INSTRUCTION: &'static str = "INST - PushClassPrivateSetter"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} diff --git a/boa_engine/src/vm/opcode/push/literal.rs b/boa_engine/src/vm/opcode/push/literal.rs index 28e51ac74ef..396f21cd8b3 100644 --- a/boa_engine/src/vm/opcode/push/literal.rs +++ b/boa_engine/src/vm/opcode/push/literal.rs @@ -10,14 +10,31 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct PushLiteral; +impl PushLiteral { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let value = context.vm.frame().code_block.literals[index].clone(); + context.vm.push(value); + Ok(CompletionType::Normal) + } +} + impl Operation for PushLiteral { const NAME: &'static str = "PushLiteral"; const INSTRUCTION: &'static str = "INST - PushLiteral"; fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::() as usize; - let value = context.vm.frame().code_block.literals[index].clone(); - context.vm.push(value); - Ok(CompletionType::Normal) + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) } } diff --git a/boa_engine/src/vm/opcode/set/name.rs b/boa_engine/src/vm/opcode/set/name.rs index b8aa64eade5..d292d56bbd8 100644 --- a/boa_engine/src/vm/opcode/set/name.rs +++ b/boa_engine/src/vm/opcode/set/name.rs @@ -11,13 +11,9 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct ThrowMutateImmutable; -impl Operation for ThrowMutateImmutable { - const NAME: &'static str = "ThrowMutateImmutable"; - const INSTRUCTION: &'static str = "INST - ThrowMutateImmutable"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = &context.vm.frame().code_block.names[index as usize]; +impl ThrowMutateImmutable { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = &context.vm.frame().code_block.names[index]; Err(JsNativeError::typ() .with_message(format!( @@ -28,6 +24,26 @@ impl Operation for ThrowMutateImmutable { } } +impl Operation for ThrowMutateImmutable { + const NAME: &'static str = "ThrowMutateImmutable"; + const INSTRUCTION: &'static str = "INST - ThrowMutateImmutable"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} + /// `SetName` implements the Opcode Operation for `Opcode::SetName` /// /// Operation: @@ -35,13 +51,9 @@ impl Operation for ThrowMutateImmutable { #[derive(Debug, Clone, Copy)] pub(crate) struct SetName; -impl Operation for SetName { - const NAME: &'static str = "SetName"; - const INSTRUCTION: &'static str = "INST - SetName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let mut binding_locator = context.vm.frame().code_block.bindings[index as usize]; +impl SetName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let mut binding_locator = context.vm.frame().code_block.bindings[index]; let value = context.vm.pop(); context.find_runtime_binding(&mut binding_locator)?; @@ -58,6 +70,26 @@ impl Operation for SetName { } } +impl Operation for SetName { + const NAME: &'static str = "SetName"; + const INSTRUCTION: &'static str = "INST - SetName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} + /// `SetNameByLocator` implements the Opcode Operation for `Opcode::SetNameByLocator` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/set/private.rs b/boa_engine/src/vm/opcode/set/private.rs index ad3693d355c..73104230b06 100644 --- a/boa_engine/src/vm/opcode/set/private.rs +++ b/boa_engine/src/vm/opcode/set/private.rs @@ -14,13 +14,9 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct SetPrivateField; -impl Operation for SetPrivateField { - const NAME: &'static str = "SetPrivateField"; - const INSTRUCTION: &'static str = "INST - SetPrivateField"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl SetPrivateField { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let value = context.vm.pop(); let object = context.vm.pop(); let base_obj = object.to_object(context)?; @@ -37,6 +33,26 @@ impl Operation for SetPrivateField { } } +impl Operation for SetPrivateField { + const NAME: &'static str = "SetPrivateField"; + const INSTRUCTION: &'static str = "INST - SetPrivateField"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `DefinePrivateField` implements the Opcode Operation for `Opcode::DefinePrivateField` /// /// Operation: @@ -44,13 +60,10 @@ impl Operation for SetPrivateField { #[derive(Debug, Clone, Copy)] pub(crate) struct DefinePrivateField; -impl Operation for DefinePrivateField { - const NAME: &'static str = "DefinePrivateField"; - const INSTRUCTION: &'static str = "INST - DefinePrivateField"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl DefinePrivateField { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let value = context.vm.pop(); let object = context.vm.pop(); let object = object @@ -65,6 +78,26 @@ impl Operation for DefinePrivateField { } } +impl Operation for DefinePrivateField { + const NAME: &'static str = "DefinePrivateField"; + const INSTRUCTION: &'static str = "INST - DefinePrivateField"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `SetPrivateMethod` implements the Opcode Operation for `Opcode::SetPrivateMethod` /// /// Operation: @@ -72,13 +105,10 @@ impl Operation for DefinePrivateField { #[derive(Debug, Clone, Copy)] pub(crate) struct SetPrivateMethod; -impl Operation for SetPrivateMethod { - const NAME: &'static str = "SetPrivateMethod"; - const INSTRUCTION: &'static str = "INST - SetPrivateMethod"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl SetPrivateMethod { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let value = context.vm.pop(); let value = value.as_callable().expect("method must be callable"); @@ -112,6 +142,26 @@ impl Operation for SetPrivateMethod { } } +impl Operation for SetPrivateMethod { + const NAME: &'static str = "SetPrivateMethod"; + const INSTRUCTION: &'static str = "INST - SetPrivateMethod"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `SetPrivateSetter` implements the Opcode Operation for `Opcode::SetPrivateSetter` /// /// Operation: @@ -119,13 +169,10 @@ impl Operation for SetPrivateMethod { #[derive(Debug, Clone, Copy)] pub(crate) struct SetPrivateSetter; -impl Operation for SetPrivateSetter { - const NAME: &'static str = "SetPrivateSetter"; - const INSTRUCTION: &'static str = "INST - SetPrivateSetter"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl SetPrivateSetter { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let value = context.vm.pop(); let value = value.as_callable().expect("setter must be callable"); let object = context.vm.pop(); @@ -150,6 +197,26 @@ impl Operation for SetPrivateSetter { } } +impl Operation for SetPrivateSetter { + const NAME: &'static str = "SetPrivateSetter"; + const INSTRUCTION: &'static str = "INST - SetPrivateSetter"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `SetPrivateGetter` implements the Opcode Operation for `Opcode::SetPrivateGetter` /// /// Operation: @@ -157,13 +224,10 @@ impl Operation for SetPrivateSetter { #[derive(Debug, Clone, Copy)] pub(crate) struct SetPrivateGetter; -impl Operation for SetPrivateGetter { - const NAME: &'static str = "SetPrivateGetter"; - const INSTRUCTION: &'static str = "INST - SetPrivateGetter"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); +impl SetPrivateGetter { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { + let name = context.vm.frame().code_block.names[index].clone(); let value = context.vm.pop(); let value = value.as_callable().expect("getter must be callable"); let object = context.vm.pop(); @@ -187,3 +251,23 @@ impl Operation for SetPrivateGetter { Ok(CompletionType::Normal) } } + +impl Operation for SetPrivateGetter { + const NAME: &'static str = "SetPrivateGetter"; + const INSTRUCTION: &'static str = "INST - SetPrivateGetter"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} diff --git a/boa_engine/src/vm/opcode/set/property.rs b/boa_engine/src/vm/opcode/set/property.rs index 245f3184619..8a3bdbeb208 100644 --- a/boa_engine/src/vm/opcode/set/property.rs +++ b/boa_engine/src/vm/opcode/set/property.rs @@ -14,13 +14,8 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub(crate) struct SetPropertyByName; -impl Operation for SetPropertyByName { - const NAME: &'static str = "SetPropertyByName"; - const INSTRUCTION: &'static str = "INST - SetPropertyByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); - +impl SetPropertyByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let value = context.vm.pop(); let receiver = context.vm.pop(); let object = context.vm.pop(); @@ -30,9 +25,7 @@ impl Operation for SetPropertyByName { object.to_object(context)? }; - let name: PropertyKey = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let name: PropertyKey = context.vm.frame().code_block.names[index].clone().into(); let succeeded = object.__set__(name.clone(), value.clone(), receiver, context)?; if !succeeded && context.vm.frame().code_block.strict() { @@ -45,6 +38,26 @@ impl Operation for SetPropertyByName { } } +impl Operation for SetPropertyByName { + const NAME: &'static str = "SetPropertyByName"; + const INSTRUCTION: &'static str = "INST - SetPropertyByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::(); + Self::operation(context, index as usize) + } +} + /// `SetPropertyByValue` implements the Opcode Operation for `Opcode::SetPropertyByValue` /// /// Operation: @@ -156,18 +169,12 @@ impl Operation for SetPropertyByValue { #[derive(Debug, Clone, Copy)] pub(crate) struct SetPropertyGetterByName; -impl Operation for SetPropertyGetterByName { - const NAME: &'static str = "SetPropertyGetterByName"; - const INSTRUCTION: &'static str = "INST - SetPropertyGetterByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl SetPropertyGetterByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let value = context.vm.pop(); let object = context.vm.pop(); let object = object.to_object(context)?; - let name = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let name = context.vm.frame().code_block.names[index].clone().into(); let set = object .__get_own_property__(&name, context)? .as_ref() @@ -187,6 +194,26 @@ impl Operation for SetPropertyGetterByName { } } +impl Operation for SetPropertyGetterByName { + const NAME: &'static str = "SetPropertyGetterByName"; + const INSTRUCTION: &'static str = "INST - SetPropertyGetterByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `SetPropertyGetterByValue` implements the Opcode Operation for `Opcode::SetPropertyGetterByValue` /// /// Operation: @@ -230,18 +257,12 @@ impl Operation for SetPropertyGetterByValue { #[derive(Debug, Clone, Copy)] pub(crate) struct SetPropertySetterByName; -impl Operation for SetPropertySetterByName { - const NAME: &'static str = "SetPropertySetterByName"; - const INSTRUCTION: &'static str = "INST - SetPropertySetterByName"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let index = context.vm.read::(); +impl SetPropertySetterByName { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let value = context.vm.pop(); let object = context.vm.pop(); let object = object.to_object(context)?; - let name = context.vm.frame().code_block.names[index as usize] - .clone() - .into(); + let name = context.vm.frame().code_block.names[index].clone().into(); let get = object .__get_own_property__(&name, context)? .as_ref() @@ -261,6 +282,26 @@ impl Operation for SetPropertySetterByName { } } +impl Operation for SetPropertySetterByName { + const NAME: &'static str = "SetPropertySetterByName"; + const INSTRUCTION: &'static str = "INST - SetPropertySetterByName"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let index = context.vm.read::() as usize; + Self::operation(context, index) + } +} + /// `SetPropertySetterByValue` implements the Opcode Operation for `Opcode::SetPropertySetterByValue` /// /// Operation: diff --git a/boa_engine/src/vm/opcode/templates/mod.rs b/boa_engine/src/vm/opcode/templates/mod.rs index 446808ec7b2..ebb58fa7648 100644 --- a/boa_engine/src/vm/opcode/templates/mod.rs +++ b/boa_engine/src/vm/opcode/templates/mod.rs @@ -38,14 +38,9 @@ impl Operation for TemplateLookup { #[derive(Debug, Clone, Copy)] pub(crate) struct TemplateCreate; -impl Operation for TemplateCreate { - const NAME: &'static str = "TemplateCreate"; - const INSTRUCTION: &'static str = "INST - TemplateCreate"; - - fn execute(context: &mut Context<'_>) -> JsResult { - let count = context.vm.read::(); - let site = context.vm.read::(); - +impl TemplateCreate { + #[allow(clippy::unnecessary_wraps)] + fn operation(context: &mut Context<'_>, count: u32, site: u64) -> JsResult { let template = Array::array_create(count.into(), None, context).expect("cannot fail per spec"); let raw_obj = @@ -102,3 +97,26 @@ impl Operation for TemplateCreate { Ok(CompletionType::Normal) } } + +impl Operation for TemplateCreate { + const NAME: &'static str = "TemplateCreate"; + const INSTRUCTION: &'static str = "INST - TemplateCreate"; + + fn execute(context: &mut Context<'_>) -> JsResult { + let count = u32::from(context.vm.read::()); + let site = context.vm.read::(); + Self::operation(context, count, site) + } + + fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult { + let count = u32::from(context.vm.read::()); + let site = context.vm.read::(); + Self::operation(context, count, site) + } + + fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult { + let count = context.vm.read::(); + let site = context.vm.read::(); + Self::operation(context, count, site) + } +}