Browse Source

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.
pull/2559/head
raskad 2 years ago
parent
commit
6c8e9c7070
  1. 23
      boa_engine/src/builtins/function/mod.rs
  2. 5
      boa_engine/src/bytecompiler/class.rs
  3. 2
      boa_engine/src/bytecompiler/mod.rs
  4. 8
      boa_engine/src/vm/code_block.rs
  5. 2
      boa_engine/src/vm/flowgraph/mod.rs
  6. 12
      boa_engine/src/vm/opcode/get/function.rs
  7. 6
      boa_engine/src/vm/opcode/get/generator.rs
  8. 12
      boa_engine/src/vm/opcode/mod.rs

23
boa_engine/src/builtins/function/mod.rs

@ -616,9 +616,16 @@ impl BuiltInFunctionObject {
let environments = context.realm.environments.pop_to_global(); let environments = context.realm.environments.pop_to_global();
let function_object = if generator { 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 { } 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); context.realm.environments.extend(environments);
@ -636,7 +643,7 @@ impl BuiltInFunctionObject {
let environments = context.realm.environments.pop_to_global(); let environments = context.realm.environments.pop_to_global();
let function_object = 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); context.realm.environments.extend(environments);
Ok(function_object) Ok(function_object)
@ -648,8 +655,14 @@ impl BuiltInFunctionObject {
)?; )?;
let environments = context.realm.environments.pop_to_global(); let environments = context.realm.environments.pop_to_global();
let function_object = let function_object = crate::vm::create_function_object(
crate::vm::create_function_object(code, r#async, false, Some(prototype), context); code,
r#async,
false,
Some(prototype),
false,
context,
);
context.realm.environments.extend(environments); context.realm.environments.extend(environments);
Ok(function_object) Ok(function_object)

5
boa_engine/src/bytecompiler/class.rs

@ -138,6 +138,7 @@ impl ByteCompiler<'_, '_> {
let index = self.code_block.functions.len() as u32; let index = self.code_block.functions.len() as u32;
self.code_block.functions.push(code); self.code_block.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
if let Some(node) = class.super_ref() { if let Some(node) = class.super_ref() {
@ -320,6 +321,7 @@ impl ByteCompiler<'_, '_> {
let index = self.code_block.functions.len() as u32; let index = self.code_block.functions.len() as u32;
self.code_block.functions.push(code); self.code_block.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0);
self.emit_opcode(Opcode::PushClassField); self.emit_opcode(Opcode::PushClassField);
} }
ClassElement::PrivateFieldDefinition(name, field) => { ClassElement::PrivateFieldDefinition(name, field) => {
@ -362,6 +364,7 @@ impl ByteCompiler<'_, '_> {
let index = self.code_block.functions.len() as u32; let index = self.code_block.functions.len() as u32;
self.code_block.functions.push(code); self.code_block.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0);
self.emit(Opcode::PushClassFieldPrivate, &[name_index]); self.emit(Opcode::PushClassFieldPrivate, &[name_index]);
} }
ClassElement::StaticFieldDefinition(name, field) => { ClassElement::StaticFieldDefinition(name, field) => {
@ -414,6 +417,7 @@ impl ByteCompiler<'_, '_> {
let index = self.code_block.functions.len() as u32; let index = self.code_block.functions.len() as u32;
self.code_block.functions.push(code); self.code_block.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0);
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);
self.emit(Opcode::Call, &[0]); self.emit(Opcode::Call, &[0]);
if let Some(name_index) = name_index { if let Some(name_index) = name_index {
@ -454,6 +458,7 @@ impl ByteCompiler<'_, '_> {
let index = self.code_block.functions.len() as u32; let index = self.code_block.functions.len() as u32;
self.code_block.functions.push(code); self.code_block.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0);
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);
self.emit(Opcode::Call, &[0]); self.emit(Opcode::Call, &[0]);
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);

2
boa_engine/src/bytecompiler/mod.rs

@ -1083,6 +1083,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
} else { } else {
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
} }
self.emit_u8(0);
match node_kind { match node_kind {
NodeKind::Declaration => { NodeKind::Declaration => {
@ -1158,6 +1159,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
} else { } else {
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
} }
self.emit_u8(1);
match node_kind { match node_kind {
NodeKind::Declaration => { NodeKind::Declaration => {

8
boa_engine/src/vm/code_block.rs

@ -270,7 +270,7 @@ impl CodeBlock {
| Opcode::GetGenerator | Opcode::GetGenerator
| Opcode::GetGeneratorAsync => { | Opcode::GetGeneratorAsync => {
let operand = self.read::<u32>(*pc); let operand = self.read::<u32>(*pc);
*pc += size_of::<u32>(); *pc += size_of::<u32>() + size_of::<u8>();
format!( format!(
"{operand:04}: '{:?}' (length: {})", "{operand:04}: '{:?}' (length: {})",
interner.resolve_expect(self.functions[operand as usize].name), interner.resolve_expect(self.functions[operand as usize].name),
@ -518,6 +518,7 @@ pub(crate) fn create_function_object(
r#async: bool, r#async: bool,
arrow: bool, arrow: bool,
prototype: Option<JsObject>, prototype: Option<JsObject>,
method: bool,
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsObject { ) -> JsObject {
let _timer = Profiler::global().start_event("JsVmFunction::new", "vm"); let _timer = Profiler::global().start_event("JsVmFunction::new", "vm");
@ -612,7 +613,7 @@ pub(crate) fn create_function_object(
constructor constructor
.define_property_or_throw(js_string!("name"), name_property, context) .define_property_or_throw(js_string!("name"), name_property, context)
.expect("failed to define the name property of the function"); .expect("failed to define the name property of the function");
if !r#async && !arrow { if !r#async && !arrow && !method {
constructor constructor
.define_property_or_throw(js_string!("prototype"), prototype_property, context) .define_property_or_throw(js_string!("prototype"), prototype_property, context)
.expect("failed to define the prototype property of the function"); .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( pub(crate) fn create_generator_function_object(
code: Gc<CodeBlock>, code: Gc<CodeBlock>,
r#async: bool, r#async: bool,
method: bool,
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsObject { ) -> JsObject {
let function_prototype = if r#async { let function_prototype = if r#async {
@ -701,9 +703,11 @@ pub(crate) fn create_generator_function_object(
.configurable(false) .configurable(false)
.build(); .build();
if !method {
constructor constructor
.define_property_or_throw(js_string!("prototype"), prototype_property, context) .define_property_or_throw(js_string!("prototype"), prototype_property, context)
.expect("failed to define the prototype property of the generator function"); .expect("failed to define the prototype property of the generator function");
}
constructor constructor
.define_property_or_throw(js_string!("name"), name_property, context) .define_property_or_throw(js_string!("name"), name_property, context)
.expect("failed to define the name property of the generator function"); .expect("failed to define the name property of the generator function");

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

@ -310,7 +310,7 @@ impl CodeBlock {
let fn_name = interner let fn_name = interner
.resolve_expect(self.functions[operand as usize].name) .resolve_expect(self.functions[operand as usize].name)
.to_string(); .to_string();
pc += size_of::<u32>(); pc += size_of::<u32>() + size_of::<u8>();
let label = format!( let label = format!(
"{opcode_str} '{fn_name}' (length: {})", "{opcode_str} '{fn_name}' (length: {})",
self.functions[operand as usize].length self.functions[operand as usize].length

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

@ -16,8 +16,9 @@ impl Operation for GetArrowFunction {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
context.vm.read::<u8>();
let code = context.vm.frame().code_block.functions[index as usize].clone(); 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); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
} }
@ -36,8 +37,9 @@ impl Operation for GetAsyncArrowFunction {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
context.vm.read::<u8>();
let code = context.vm.frame().code_block.functions[index as usize].clone(); 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); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
} }
@ -56,8 +58,9 @@ impl Operation for GetFunction {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let method = context.vm.read::<u8>() != 0;
let code = context.vm.frame().code_block.functions[index as usize].clone(); 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); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
} }
@ -76,8 +79,9 @@ impl Operation for GetFunctionAsync {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let method = context.vm.read::<u8>() != 0;
let code = context.vm.frame().code_block.functions[index as usize].clone(); 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); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
} }

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

@ -16,8 +16,9 @@ impl Operation for GetGenerator {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let method = context.vm.read::<u8>() != 0;
let code = context.vm.frame().code_block.functions[index as usize].clone(); 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); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
} }
@ -36,8 +37,9 @@ impl Operation for GetGeneratorAsync {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let method = context.vm.read::<u8>() != 0;
let code = context.vm.frame().code_block.functions[index as usize].clone(); 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); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
} }

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

@ -1207,42 +1207,42 @@ generate_impl! {
/// Get arrow function from the pre-compiled inner functions. /// Get arrow function from the pre-compiled inner functions.
/// ///
/// Operands: address: `u32` /// Operands: address: `u32`, method: `u8`
/// ///
/// Stack: **=>** func /// Stack: **=>** func
GetArrowFunction, GetArrowFunction,
/// Get async arrow function from the pre-compiled inner functions. /// Get async arrow function from the pre-compiled inner functions.
/// ///
/// Operands: address: `u32` /// Operands: address: `u32`, method: `u8`
/// ///
/// Stack: **=>** func /// Stack: **=>** func
GetAsyncArrowFunction, GetAsyncArrowFunction,
/// Get function from the pre-compiled inner functions. /// Get function from the pre-compiled inner functions.
/// ///
/// Operands: address: `u32` /// Operands: address: `u32`, method: `u8`
/// ///
/// Stack: **=>** func /// Stack: **=>** func
GetFunction, GetFunction,
/// Get async function from the pre-compiled inner functions. /// Get async function from the pre-compiled inner functions.
/// ///
/// Operands: address: `u32` /// Operands: address: `u32`, method: `u8`
/// ///
/// Stack: **=>** func /// Stack: **=>** func
GetFunctionAsync, GetFunctionAsync,
/// Get generator function from the pre-compiled inner functions. /// Get generator function from the pre-compiled inner functions.
/// ///
/// Operands: address: `u32` /// Operands: address: `u32`, method: `u8`
/// ///
/// Stack: **=>** func /// Stack: **=>** func
GetGenerator, GetGenerator,
/// Get async generator function from the pre-compiled inner functions. /// Get async generator function from the pre-compiled inner functions.
/// ///
/// Operands: address: `u32` /// Operands: address: `u32`, method: `u8`
/// ///
/// Stack: **=>** func /// Stack: **=>** func
GetGeneratorAsync, GetGeneratorAsync,

Loading…
Cancel
Save