From 6c8e9c707000e805b3f60f06965c07842fd77a17 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Tue, 24 Jan 2023 16:48:51 +0000 Subject: [PATCH] Avoid creating `prototype` property on methods (#2553) This Pull Request changes the following: - Stop creating a `prototype` property on class methods by passing a flag to the relevant opcodes. --- boa_engine/src/builtins/function/mod.rs | 23 ++++++++++++++++++----- boa_engine/src/bytecompiler/class.rs | 5 +++++ boa_engine/src/bytecompiler/mod.rs | 2 ++ boa_engine/src/vm/code_block.rs | 14 +++++++++----- boa_engine/src/vm/flowgraph/mod.rs | 2 +- boa_engine/src/vm/opcode/get/function.rs | 12 ++++++++---- boa_engine/src/vm/opcode/get/generator.rs | 6 ++++-- boa_engine/src/vm/opcode/mod.rs | 12 ++++++------ 8 files changed, 53 insertions(+), 23 deletions(-) diff --git a/boa_engine/src/builtins/function/mod.rs b/boa_engine/src/builtins/function/mod.rs index cdb035daf3..abebc772b3 100644 --- a/boa_engine/src/builtins/function/mod.rs +++ b/boa_engine/src/builtins/function/mod.rs @@ -616,9 +616,16 @@ impl BuiltInFunctionObject { let environments = context.realm.environments.pop_to_global(); let function_object = if generator { - crate::vm::create_generator_function_object(code, r#async, context) + crate::vm::create_generator_function_object(code, r#async, false, context) } else { - crate::vm::create_function_object(code, r#async, false, Some(prototype), context) + crate::vm::create_function_object( + code, + r#async, + false, + Some(prototype), + false, + context, + ) }; context.realm.environments.extend(environments); @@ -636,7 +643,7 @@ impl BuiltInFunctionObject { let environments = context.realm.environments.pop_to_global(); let function_object = - crate::vm::create_generator_function_object(code, r#async, context); + crate::vm::create_generator_function_object(code, r#async, false, context); context.realm.environments.extend(environments); Ok(function_object) @@ -648,8 +655,14 @@ impl BuiltInFunctionObject { )?; let environments = context.realm.environments.pop_to_global(); - let function_object = - crate::vm::create_function_object(code, r#async, false, Some(prototype), context); + let function_object = crate::vm::create_function_object( + code, + r#async, + false, + Some(prototype), + false, + context, + ); context.realm.environments.extend(environments); Ok(function_object) diff --git a/boa_engine/src/bytecompiler/class.rs b/boa_engine/src/bytecompiler/class.rs index 1e6f24f7ca..6942b2716f 100644 --- a/boa_engine/src/bytecompiler/class.rs +++ b/boa_engine/src/bytecompiler/class.rs @@ -138,6 +138,7 @@ impl ByteCompiler<'_, '_> { let index = self.code_block.functions.len() as u32; self.code_block.functions.push(code); self.emit(Opcode::GetFunction, &[index]); + self.emit_u8(0); self.emit_opcode(Opcode::Dup); if let Some(node) = class.super_ref() { @@ -320,6 +321,7 @@ impl ByteCompiler<'_, '_> { let index = self.code_block.functions.len() as u32; self.code_block.functions.push(code); self.emit(Opcode::GetFunction, &[index]); + self.emit_u8(0); self.emit_opcode(Opcode::PushClassField); } ClassElement::PrivateFieldDefinition(name, field) => { @@ -362,6 +364,7 @@ impl ByteCompiler<'_, '_> { let index = self.code_block.functions.len() as u32; self.code_block.functions.push(code); self.emit(Opcode::GetFunction, &[index]); + self.emit_u8(0); self.emit(Opcode::PushClassFieldPrivate, &[name_index]); } ClassElement::StaticFieldDefinition(name, field) => { @@ -414,6 +417,7 @@ impl ByteCompiler<'_, '_> { let index = self.code_block.functions.len() as u32; self.code_block.functions.push(code); self.emit(Opcode::GetFunction, &[index]); + self.emit_u8(0); self.emit_opcode(Opcode::SetHomeObject); self.emit(Opcode::Call, &[0]); if let Some(name_index) = name_index { @@ -454,6 +458,7 @@ impl ByteCompiler<'_, '_> { let index = self.code_block.functions.len() as u32; self.code_block.functions.push(code); self.emit(Opcode::GetFunction, &[index]); + self.emit_u8(0); self.emit_opcode(Opcode::SetHomeObject); self.emit(Opcode::Call, &[0]); self.emit_opcode(Opcode::Pop); diff --git a/boa_engine/src/bytecompiler/mod.rs b/boa_engine/src/bytecompiler/mod.rs index 3c68265c79..839d1e25d2 100644 --- a/boa_engine/src/bytecompiler/mod.rs +++ b/boa_engine/src/bytecompiler/mod.rs @@ -1083,6 +1083,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } else { self.emit(Opcode::GetFunction, &[index]); } + self.emit_u8(0); match node_kind { NodeKind::Declaration => { @@ -1158,6 +1159,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { } else { self.emit(Opcode::GetFunction, &[index]); } + self.emit_u8(1); match node_kind { NodeKind::Declaration => { diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index 966bc4ec84..5c6ba6ec59 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -270,7 +270,7 @@ impl CodeBlock { | Opcode::GetGenerator | Opcode::GetGeneratorAsync => { let operand = self.read::(*pc); - *pc += size_of::(); + *pc += size_of::() + size_of::(); format!( "{operand:04}: '{:?}' (length: {})", interner.resolve_expect(self.functions[operand as usize].name), @@ -518,6 +518,7 @@ pub(crate) fn create_function_object( r#async: bool, arrow: bool, prototype: Option, + method: bool, context: &mut Context<'_>, ) -> JsObject { let _timer = Profiler::global().start_event("JsVmFunction::new", "vm"); @@ -612,7 +613,7 @@ pub(crate) fn create_function_object( constructor .define_property_or_throw(js_string!("name"), name_property, context) .expect("failed to define the name property of the function"); - if !r#async && !arrow { + if !r#async && !arrow && !method { constructor .define_property_or_throw(js_string!("prototype"), prototype_property, context) .expect("failed to define the prototype property of the function"); @@ -625,6 +626,7 @@ pub(crate) fn create_function_object( pub(crate) fn create_generator_function_object( code: Gc, r#async: bool, + method: bool, context: &mut Context<'_>, ) -> JsObject { let function_prototype = if r#async { @@ -701,9 +703,11 @@ pub(crate) fn create_generator_function_object( .configurable(false) .build(); - constructor - .define_property_or_throw(js_string!("prototype"), prototype_property, context) - .expect("failed to define the prototype property of the generator function"); + if !method { + constructor + .define_property_or_throw(js_string!("prototype"), prototype_property, context) + .expect("failed to define the prototype property of the generator function"); + } constructor .define_property_or_throw(js_string!("name"), name_property, context) .expect("failed to define the name property of the generator function"); diff --git a/boa_engine/src/vm/flowgraph/mod.rs b/boa_engine/src/vm/flowgraph/mod.rs index 8699900756..d0a1c2ce04 100644 --- a/boa_engine/src/vm/flowgraph/mod.rs +++ b/boa_engine/src/vm/flowgraph/mod.rs @@ -310,7 +310,7 @@ impl CodeBlock { let fn_name = interner .resolve_expect(self.functions[operand as usize].name) .to_string(); - pc += size_of::(); + pc += size_of::() + size_of::(); let label = format!( "{opcode_str} '{fn_name}' (length: {})", self.functions[operand as usize].length diff --git a/boa_engine/src/vm/opcode/get/function.rs b/boa_engine/src/vm/opcode/get/function.rs index c361058954..bfff1e9915 100644 --- a/boa_engine/src/vm/opcode/get/function.rs +++ b/boa_engine/src/vm/opcode/get/function.rs @@ -16,8 +16,9 @@ impl Operation for 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(code, false, true, None, context); + let function = create_function_object(code, false, true, None, false, context); context.vm.push(function); Ok(ShouldExit::False) } @@ -36,8 +37,9 @@ impl Operation for 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(code, true, true, None, context); + let function = create_function_object(code, true, true, None, false, context); context.vm.push(function); Ok(ShouldExit::False) } @@ -56,8 +58,9 @@ impl Operation for GetFunction { fn execute(context: &mut Context<'_>) -> JsResult { let index = context.vm.read::(); + let method = context.vm.read::() != 0; let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_function_object(code, false, false, None, context); + let function = create_function_object(code, false, false, None, method, context); context.vm.push(function); Ok(ShouldExit::False) } @@ -76,8 +79,9 @@ impl Operation for GetFunctionAsync { fn execute(context: &mut Context<'_>) -> JsResult { let index = context.vm.read::(); + let method = context.vm.read::() != 0; let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_function_object(code, true, false, None, context); + let function = create_function_object(code, true, false, None, method, context); context.vm.push(function); Ok(ShouldExit::False) } diff --git a/boa_engine/src/vm/opcode/get/generator.rs b/boa_engine/src/vm/opcode/get/generator.rs index 4b23dcdc04..6210ed26aa 100644 --- a/boa_engine/src/vm/opcode/get/generator.rs +++ b/boa_engine/src/vm/opcode/get/generator.rs @@ -16,8 +16,9 @@ impl Operation for GetGenerator { fn execute(context: &mut Context<'_>) -> JsResult { let index = context.vm.read::(); + let method = context.vm.read::() != 0; let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_generator_function_object(code, false, context); + let function = create_generator_function_object(code, false, method, context); context.vm.push(function); Ok(ShouldExit::False) } @@ -36,8 +37,9 @@ impl Operation for GetGeneratorAsync { fn execute(context: &mut Context<'_>) -> JsResult { let index = context.vm.read::(); + let method = context.vm.read::() != 0; let code = context.vm.frame().code_block.functions[index as usize].clone(); - let function = create_generator_function_object(code, true, context); + let function = create_generator_function_object(code, true, method, context); context.vm.push(function); Ok(ShouldExit::False) } diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index d8ceb8883d..d4ad0e5a16 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -1207,42 +1207,42 @@ generate_impl! { /// Get arrow function from the pre-compiled inner functions. /// - /// Operands: address: `u32` + /// Operands: address: `u32`, method: `u8` /// /// Stack: **=>** func GetArrowFunction, /// Get async arrow function from the pre-compiled inner functions. /// - /// Operands: address: `u32` + /// Operands: address: `u32`, method: `u8` /// /// Stack: **=>** func GetAsyncArrowFunction, /// Get function from the pre-compiled inner functions. /// - /// Operands: address: `u32` + /// Operands: address: `u32`, method: `u8` /// /// Stack: **=>** func GetFunction, /// Get async function from the pre-compiled inner functions. /// - /// Operands: address: `u32` + /// Operands: address: `u32`, method: `u8` /// /// Stack: **=>** func GetFunctionAsync, /// Get generator function from the pre-compiled inner functions. /// - /// Operands: address: `u32` + /// Operands: address: `u32`, method: `u8` /// /// Stack: **=>** func GetGenerator, /// Get async generator function from the pre-compiled inner functions. /// - /// Operands: address: `u32` + /// Operands: address: `u32`, method: `u8` /// /// Stack: **=>** func GetGeneratorAsync,