From 2c12bae7b6221883653e2d8959a29a736408a163 Mon Sep 17 00:00:00 2001 From: Haled Odat <8566042+HalidOdat@users.noreply.github.com> Date: Tue, 31 Oct 2023 23:10:30 +0100 Subject: [PATCH] Unify generator and ordinary function creation (#3441) * Unify generator and ordinary function creation * Remove GetGenerator opcode * Remove GetArrowFunction opcode --- boa_engine/src/builtins/function/mod.rs | 80 +++------ boa_engine/src/bytecompiler/class.rs | 25 +-- boa_engine/src/bytecompiler/declarations.rs | 26 +-- boa_engine/src/bytecompiler/function.rs | 14 +- boa_engine/src/bytecompiler/mod.rs | 40 +---- boa_engine/src/context/intrinsics.rs | 32 ++++ boa_engine/src/module/source.rs | 18 +- boa_engine/src/object/mod.rs | 39 +---- boa_engine/src/vm/code_block.rs | 176 +++++++------------- boa_engine/src/vm/flowgraph/mod.rs | 10 +- boa_engine/src/vm/mod.rs | 3 +- boa_engine/src/vm/opcode/get/function.rs | 55 +----- boa_engine/src/vm/opcode/get/generator.rs | 42 ----- boa_engine/src/vm/opcode/get/mod.rs | 2 - boa_engine/src/vm/opcode/mod.rs | 22 +-- 15 files changed, 161 insertions(+), 423 deletions(-) delete mode 100644 boa_engine/src/vm/opcode/get/generator.rs diff --git a/boa_engine/src/builtins/function/mod.rs b/boa_engine/src/builtins/function/mod.rs index 5940e365ff..e6c1355950 100644 --- a/boa_engine/src/builtins/function/mod.rs +++ b/boa_engine/src/builtins/function/mod.rs @@ -409,7 +409,7 @@ impl BuiltInFunctionObject { // 22. Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto). let prototype = get_prototype_from_constructor(&new_target, default, context)?; - if let Some((body_arg, args)) = args.split_last() { + let (parameters, body) = if let Some((body_arg, args)) = args.split_last() { let parameters = if args.is_empty() { FormalParameterList::default() } else { @@ -551,66 +551,28 @@ impl BuiltInFunctionObject { .into()); } - let code = FunctionCompiler::new() - .name(Sym::ANONYMOUS) - .generator(generator) - .r#async(r#async) - .compile( - ¶meters, - &body, - context.realm().environment().compile_env(), - context.realm().environment().compile_env(), - context, - ); - - let environments = context.vm.environments.pop_to_global(); - - let function_object = if generator { - crate::vm::create_generator_function_object(code, Some(prototype), context) - } else { - crate::vm::create_function_object(code, prototype, context) - }; + (parameters, body) + } else { + (FormalParameterList::default(), FunctionBody::default()) + }; - context.vm.environments.extend(environments); + let code = FunctionCompiler::new() + .name(Sym::ANONYMOUS) + .generator(generator) + .r#async(r#async) + .compile( + ¶meters, + &body, + context.realm().environment().compile_env(), + context.realm().environment().compile_env(), + context, + ); - Ok(function_object) - } else if generator { - let code = FunctionCompiler::new() - .name(Sym::ANONYMOUS) - .generator(true) - .r#async(r#async) - .compile( - &FormalParameterList::default(), - &FunctionBody::default(), - context.realm().environment().compile_env(), - context.realm().environment().compile_env(), - context, - ); - - let environments = context.vm.environments.pop_to_global(); - let function_object = - crate::vm::create_generator_function_object(code, Some(prototype), context); - context.vm.environments.extend(environments); - - Ok(function_object) - } else { - let code = FunctionCompiler::new() - .r#async(r#async) - .name(Sym::ANONYMOUS) - .compile( - &FormalParameterList::default(), - &FunctionBody::default(), - context.realm().environment().compile_env(), - context.realm().environment().compile_env(), - context, - ); - - let environments = context.vm.environments.pop_to_global(); - let function_object = crate::vm::create_function_object(code, prototype, context); - context.vm.environments.extend(environments); - - Ok(function_object) - } + let environments = context.vm.environments.pop_to_global(); + let function_object = crate::vm::create_function_object(code, prototype, context); + context.vm.environments.extend(environments); + + Ok(function_object) } /// `Function.prototype.apply ( thisArg, argArray )` diff --git a/boa_engine/src/bytecompiler/class.rs b/boa_engine/src/bytecompiler/class.rs index e95707e159..cd5a35c2bd 100644 --- a/boa_engine/src/bytecompiler/class.rs +++ b/boa_engine/src/bytecompiler/class.rs @@ -88,10 +88,7 @@ impl ByteCompiler<'_, '_> { let code = Gc::new(compiler.finish()); let index = self.push_function_to_constants(code); - self.emit( - Opcode::GetFunction, - &[Operand::Varying(index), Operand::Bool(false)], - ); + self.emit_with_varying_operand(Opcode::GetFunction, index); self.emit_opcode(Opcode::Dup); if let Some(node) = class.super_ref() { @@ -301,10 +298,7 @@ impl ByteCompiler<'_, '_> { let code = Gc::new(field_compiler.finish()); let index = self.push_function_to_constants(code); - self.emit( - Opcode::GetFunction, - &[Operand::Varying(index), Operand::Bool(false)], - ); + self.emit_with_varying_operand(Opcode::GetFunction, index); self.emit_opcode(Opcode::PushClassField); } ClassElement::PrivateFieldDefinition(name, field) => { @@ -330,10 +324,7 @@ impl ByteCompiler<'_, '_> { let code = Gc::new(field_compiler.finish()); let index = self.push_function_to_constants(code); - self.emit( - Opcode::GetFunction, - &[Operand::Varying(index), Operand::Bool(false)], - ); + self.emit_with_varying_operand(Opcode::GetFunction, index); self.emit_with_varying_operand(Opcode::PushClassFieldPrivate, name_index); } ClassElement::StaticFieldDefinition(name, field) => { @@ -554,10 +545,7 @@ impl ByteCompiler<'_, '_> { StaticElement::StaticBlock(code) => { self.emit_opcode(Opcode::Dup); let index = self.push_function_to_constants(code); - self.emit( - Opcode::GetFunction, - &[Operand::Varying(index), Operand::Bool(false)], - ); + self.emit_with_varying_operand(Opcode::GetFunction, index); self.emit_opcode(Opcode::SetHomeObject); self.emit_with_varying_operand(Opcode::Call, 0); self.emit_opcode(Opcode::Pop); @@ -566,10 +554,7 @@ impl ByteCompiler<'_, '_> { self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup); let index = self.push_function_to_constants(code); - self.emit( - Opcode::GetFunction, - &[Operand::Varying(index), Operand::Bool(false)], - ); + self.emit_with_varying_operand(Opcode::GetFunction, index); self.emit_opcode(Opcode::SetHomeObject); self.emit_with_varying_operand(Opcode::Call, 0); if let Some(name_index) = name_index { diff --git a/boa_engine/src/bytecompiler/declarations.rs b/boa_engine/src/bytecompiler/declarations.rs index 0afd0ac2a5..ffb97dbb01 100644 --- a/boa_engine/src/bytecompiler/declarations.rs +++ b/boa_engine/src/bytecompiler/declarations.rs @@ -3,10 +3,7 @@ use std::rc::Rc; use crate::{ bytecompiler::{ByteCompiler, FunctionCompiler, FunctionSpec, NodeKind}, environments::CompileTimeEnvironment, - vm::{ - create_function_object_fast, create_generator_function_object, BindingOpcode, - CodeBlockFlags, Opcode, - }, + vm::{create_function_object_fast, BindingOpcode, CodeBlockFlags, Opcode}, JsNativeError, JsResult, }; use boa_ast::{ @@ -285,11 +282,7 @@ impl ByteCompiler<'_, '_> { let _ = self.push_function_to_constants(code.clone()); // b. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv. - let function = if generator { - create_generator_function_object(code, None, self.context) - } else { - create_function_object_fast(code, false, self.context) - }; + let function = create_function_object_fast(code, self.context); // c. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false). self.context @@ -736,11 +729,7 @@ impl ByteCompiler<'_, '_> { let _ = self.push_function_to_constants(code.clone()); // b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv. - let function = if generator { - create_generator_function_object(code, None, self.context) - } else { - create_function_object_fast(code, false, self.context) - }; + let function = create_function_object_fast(code, self.context); // i. Perform ? varEnv.CreateGlobalFunctionBinding(fn, fo, true). self.context @@ -750,14 +739,7 @@ impl ByteCompiler<'_, '_> { else { // b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv. let index = self.push_function_to_constants(code); - if generator { - self.emit_with_varying_operand(Opcode::GetGenerator, index); - } else { - self.emit( - Opcode::GetFunction, - &[Operand::Varying(index), Operand::Bool(false)], - ); - } + self.emit_with_varying_operand(Opcode::GetFunction, index); // i. Let bindingExists be ! varEnv.HasBinding(fn). let binding_exists = var_env.has_binding(name); diff --git a/boa_engine/src/bytecompiler/function.rs b/boa_engine/src/bytecompiler/function.rs index d0d7f7c9e8..27c101da97 100644 --- a/boa_engine/src/bytecompiler/function.rs +++ b/boa_engine/src/bytecompiler/function.rs @@ -20,6 +20,7 @@ pub(crate) struct FunctionCompiler { r#async: bool, strict: bool, arrow: bool, + method: bool, binding_identifier: Option, } @@ -32,6 +33,7 @@ impl FunctionCompiler { r#async: false, strict: false, arrow: false, + method: false, binding_identifier: None, } } @@ -53,6 +55,11 @@ impl FunctionCompiler { self.arrow = arrow; self } + /// Indicate if the function is a method function. + pub(crate) const fn method(mut self, method: bool) -> Self { + self.method = method; + self + } /// Indicate if the function is a generator function. pub(crate) const fn generator(mut self, generator: bool) -> Self { self.generator = generator; @@ -105,9 +112,10 @@ impl FunctionCompiler { compiler .code_block_flags .set(CodeBlockFlags::IS_GENERATOR, self.generator); - compiler - .code_block_flags - .set(CodeBlockFlags::IS_ARROW, self.arrow); + compiler.code_block_flags.set( + CodeBlockFlags::HAS_PROTOTYPE_PROPERTY, + !self.arrow && !self.method, + ); if self.arrow { compiler.this_mode = ThisMode::Lexical; diff --git a/boa_engine/src/bytecompiler/mod.rs b/boa_engine/src/bytecompiler/mod.rs index e187655e92..5901f5e821 100644 --- a/boa_engine/src/bytecompiler/mod.rs +++ b/boa_engine/src/bytecompiler/mod.rs @@ -299,6 +299,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { ) -> ByteCompiler<'ctx, 'host> { let mut code_block_flags = CodeBlockFlags::empty(); code_block_flags.set(CodeBlockFlags::STRICT, strict); + code_block_flags |= CodeBlockFlags::HAS_PROTOTYPE_PROPERTY; Self { function_name: name, length: 0, @@ -1253,20 +1254,9 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { use_expr: bool, ) { let name = function.name; - let (generator, arrow) = (function.kind.is_generator(), function.kind.is_arrow()); let index = self.function(function); - - if generator { - self.emit_with_varying_operand(Opcode::GetGenerator, index); - } else if arrow { - self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]); - } else { - self.emit( - Opcode::GetFunction, - &[Operand::Varying(index), Operand::Bool(false)], - ); - } + self.emit_with_varying_operand(Opcode::GetFunction, index); match node_kind { NodeKind::Declaration => { @@ -1314,6 +1304,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { .r#async(r#async) .strict(self.strict()) .arrow(arrow) + .method(true) .binding_identifier(binding_identifier) .compile( parameters, @@ -1324,17 +1315,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { ); let index = self.push_function_to_constants(code); - - if generator { - self.emit_with_varying_operand(Opcode::GetGenerator, index); - } else if arrow { - self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]); - } else { - self.emit( - Opcode::GetFunction, - &[Operand::Varying(index), Operand::Bool(true)], - ); - } + self.emit_with_varying_operand(Opcode::GetFunction, index); } /// Compile a class method AST Node into bytecode. @@ -1368,6 +1349,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { .r#async(r#async) .strict(true) .arrow(arrow) + .method(true) .binding_identifier(binding_identifier) .compile( parameters, @@ -1378,17 +1360,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { ); let index = self.push_function_to_constants(code); - - if generator { - self.emit_with_varying_operand(Opcode::GetGenerator, index); - } else if arrow { - self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]); - } else { - self.emit( - Opcode::GetFunction, - &[Operand::Varying(index), Operand::Bool(true)], - ); - } + self.emit_with_varying_operand(Opcode::GetFunction, index); } fn call(&mut self, callable: Callable<'_>, use_expr: bool) { diff --git a/boa_engine/src/context/intrinsics.rs b/boa_engine/src/context/intrinsics.rs index 331e730813..b28cdfa0ad 100644 --- a/boa_engine/src/context/intrinsics.rs +++ b/boa_engine/src/context/intrinsics.rs @@ -1348,6 +1348,8 @@ pub(crate) struct ObjectTemplates { function: ObjectTemplate, async_function: ObjectTemplate, + generator_function: ObjectTemplate, + async_generator_function: ObjectTemplate, function_without_proto: ObjectTemplate, function_with_prototype_without_proto: ObjectTemplate, @@ -1410,12 +1412,16 @@ impl ObjectTemplates { PROTOTYPE.into(), Attribute::WRITABLE | Attribute::PERMANENT | Attribute::NON_ENUMERABLE, ); + let mut generator_function = function_with_prototype.clone(); + let mut async_generator_function = function_with_prototype.clone(); let function_with_prototype_without_proto = function_with_prototype.clone(); function.set_prototype(constructors.function().prototype()); function_with_prototype.set_prototype(constructors.function().prototype()); async_function.set_prototype(constructors.async_function().prototype()); + generator_function.set_prototype(constructors.generator_function().prototype()); + async_generator_function.set_prototype(constructors.async_generator_function().prototype()); let mut function_prototype = ordinary_object.clone(); function_prototype.property( @@ -1504,6 +1510,8 @@ impl ObjectTemplates { function_prototype, function, async_function, + generator_function, + async_generator_function, function_without_proto, function_with_prototype_without_proto, namespace, @@ -1675,6 +1683,30 @@ impl ObjectTemplates { &self.async_function } + /// Cached function object property template. + /// + /// Transitions: + /// + /// 1. `"length"`: (`READONLY`, `NON_ENUMERABLE`, `CONFIGURABLE`) + /// 2. `"name"`: (`READONLY`, `NON_ENUMERABLE`, `CONFIGURABLE`) + /// 3. `"prototype"`: (`WRITABLE`, `PERMANENT`, `NON_ENUMERABLE`) + /// 4. `__proto__`: `GeneratorFunction.prototype` + pub(crate) const fn generator_function(&self) -> &ObjectTemplate { + &self.generator_function + } + + /// Cached function object property template. + /// + /// Transitions: + /// + /// 1. `"length"`: (`READONLY`, `NON_ENUMERABLE`, `CONFIGURABLE`) + /// 2. `"name"`: (`READONLY`, `NON_ENUMERABLE`, `CONFIGURABLE`) + /// 3. `"prototype"`: (`WRITABLE`, `PERMANENT`, `NON_ENUMERABLE`) + /// 4. `__proto__`: `AsyncGeneratorFunction.prototype` + pub(crate) const fn async_generator_function(&self) -> &ObjectTemplate { + &self.async_generator_function + } + /// Cached function object without `__proto__` template. /// /// Transitions: diff --git a/boa_engine/src/module/source.rs b/boa_engine/src/module/source.rs index 331fff3924..9da65acac2 100644 --- a/boa_engine/src/module/source.rs +++ b/boa_engine/src/module/source.rs @@ -28,8 +28,8 @@ use crate::{ object::{FunctionObjectBuilder, JsPromise, RecursionLimiter}, realm::Realm, vm::{ - create_function_object_fast, create_generator_function_object, ActiveRunnable, CallFrame, - CallFrameFlags, CodeBlock, CodeBlockFlags, CompletionRecord, Opcode, + create_function_object_fast, ActiveRunnable, CallFrame, CallFrameFlags, CodeBlock, + CodeBlockFlags, CompletionRecord, Opcode, }, Context, JsArgs, JsError, JsNativeError, JsObject, JsResult, JsString, JsValue, NativeFunction, }; @@ -1583,11 +1583,7 @@ impl SourceTextModule { // are correctly resolved to the outer functions instead of as global bindings. let functions = functions .into_iter() - .map(|(spec, locator)| { - let kind = spec.kind; - - (compiler.function(spec), locator, kind) - }) + .map(|(spec, locator)| (compiler.function(spec), locator)) .collect::>(); compiler.compile_module_item_list(self.inner.code.source.items()); @@ -1656,14 +1652,10 @@ impl SourceTextModule { } // deferred initialization of function exports - for (index, locator, kind) in functions { + for (index, locator) in functions { let code = codeblock.constant_function(index as usize); - let function = if kind.is_generator() { - create_generator_function_object(code, None, context) - } else { - create_function_object_fast(code, false, context) - }; + let function = create_function_object_fast(code, context); context.vm.environments.put_lexical_value( locator.environment_index(), diff --git a/boa_engine/src/object/mod.rs b/boa_engine/src/object/mod.rs index 802f1e2d48..9bcf44a6b8 100644 --- a/boa_engine/src/object/mod.rs +++ b/boa_engine/src/object/mod.rs @@ -304,9 +304,6 @@ pub enum ObjectKind { /// The `AsyncGenerator` object kind. AsyncGenerator(AsyncGenerator), - /// The `AsyncGeneratorFunction` object kind. - AsyncGeneratorFunction(OrdinaryFunction), - /// The `Array` object kind. Array, @@ -352,9 +349,6 @@ pub enum ObjectKind { /// The `Generator` object kind. Generator(Generator), - /// The `GeneratorFunction` object kind. - GeneratorFunction(OrdinaryFunction), - /// A native rust function. NativeFunction(NativeFunctionObject), @@ -498,7 +492,7 @@ unsafe impl Trace for ObjectKind { Self::RegExpStringIterator(i) => mark(i), Self::DataView(v) => mark(v), Self::ForInIterator(i) => mark(i), - Self::OrdinaryFunction(f) | Self::GeneratorFunction(f) | Self::AsyncGeneratorFunction(f) => mark(f), + Self::OrdinaryFunction(f) => mark(f), Self::BoundFunction(f) => mark(f), Self::Generator(g) => mark(g), Self::NativeFunction(f) => mark(f), @@ -582,15 +576,6 @@ impl ObjectData { } } - /// Create the `AsyncGeneratorFunction` object data - #[must_use] - pub fn async_generator_function(function: OrdinaryFunction) -> Self { - Self { - internal_methods: &FUNCTION_INTERNAL_METHODS, - kind: ObjectKind::GeneratorFunction(function), - } - } - /// Create the `Array` object data and reference its exclusive internal methods #[must_use] pub fn array() -> Self { @@ -760,15 +745,6 @@ impl ObjectData { } } - /// Create the `GeneratorFunction` object data - #[must_use] - pub fn generator_function(function: OrdinaryFunction) -> Self { - Self { - internal_methods: &FUNCTION_INTERNAL_METHODS, - kind: ObjectKind::GeneratorFunction(function), - } - } - /// Create the `Set` object data #[must_use] pub fn set(set: OrderedSet) -> Self { @@ -1116,7 +1092,6 @@ impl Debug for ObjectKind { f.write_str(match self { Self::AsyncFromSyncIterator(_) => "AsyncFromSyncIterator", Self::AsyncGenerator(_) => "AsyncGenerator", - Self::AsyncGeneratorFunction(_) => "AsyncGeneratorFunction", Self::Array => "Array", Self::ArrayIterator(_) => "ArrayIterator", Self::ArrayBuffer(_) => "ArrayBuffer", @@ -1125,7 +1100,6 @@ impl Debug for ObjectKind { Self::OrdinaryFunction(_) => "Function", Self::BoundFunction(_) => "BoundFunction", Self::Generator(_) => "Generator", - Self::GeneratorFunction(_) => "GeneratorFunction", Self::NativeFunction { .. } => "NativeFunction", Self::RegExp(_) => "RegExp", Self::RegExpStringIterator(_) => "RegExpStringIterator", @@ -1515,10 +1489,7 @@ impl Object { #[inline] #[must_use] pub const fn is_ordinary_function(&self) -> bool { - matches!( - self.kind, - ObjectKind::OrdinaryFunction(_) | ObjectKind::GeneratorFunction(_) - ) + matches!(self.kind, ObjectKind::OrdinaryFunction(_)) } /// Gets the function data if the object is a `Function`. @@ -1526,8 +1497,7 @@ impl Object { #[must_use] pub const fn as_function(&self) -> Option<&OrdinaryFunction> { match self.kind { - ObjectKind::OrdinaryFunction(ref function) - | ObjectKind::GeneratorFunction(ref function) => Some(function), + ObjectKind::OrdinaryFunction(ref function) => Some(function), _ => None, } } @@ -1536,8 +1506,7 @@ impl Object { #[inline] pub fn as_function_mut(&mut self) -> Option<&mut OrdinaryFunction> { match self.kind { - ObjectKind::OrdinaryFunction(ref mut function) - | ObjectKind::GeneratorFunction(ref mut function) => Some(function), + ObjectKind::OrdinaryFunction(ref mut function) => Some(function), _ => None, } } diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index 8302328b21..64b1ce1c5d 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -5,9 +5,7 @@ use crate::{ builtins::function::{OrdinaryFunction, ThisMode}, environments::{BindingLocator, CompileTimeEnvironment}, - object::{JsObject, ObjectData, PROTOTYPE}, - property::PropertyDescriptor, - string::utf16, + object::{JsObject, ObjectData}, Context, JsBigInt, JsString, JsValue, }; use bitflags::bitflags; @@ -74,7 +72,9 @@ bitflags! { const IS_ASYNC = 0b1000_0000; const IS_GENERATOR = 0b0001_0000_0000; - const IS_ARROW = 0b0010_0000_0000; + + /// Arrow and method functions don't have `"prototype"` property. + const HAS_PROTOTYPE_PROPERTY = 0b0010_0000_0000; /// Trace instruction execution to `stdout`. #[cfg(feature = "trace")] @@ -269,9 +269,11 @@ impl CodeBlock { !self.is_async() && !self.is_generator() } - /// Returns true if this function an arrow function. - pub(crate) fn is_arrow(&self) -> bool { - self.flags.get().contains(CodeBlockFlags::IS_ARROW) + /// Returns true if this function has the `"prototype"` property when function object is created. + pub(crate) fn has_prototype_property(&self) -> bool { + self.flags + .get() + .contains(CodeBlockFlags::HAS_PROTOTYPE_PROPERTY) } /// Find exception [`Handler`] in the code block given the current program counter (`pc`). @@ -454,15 +456,7 @@ impl CodeBlock { Instruction::TemplateCreate { count, site } => { format!("{}, {site}", count.value()) } - Instruction::GetFunction { index, method } => { - let index = index.value() as usize; - format!( - "{index:04}: '{}' (length: {}), method: {method}", - self.constant_function(index).name().to_std_string_escaped(), - self.constant_function(index).length - ) - } - Instruction::GetArrowFunction { index } | Instruction::GetGenerator { index } => { + Instruction::GetFunction { index } => { let index = index.value() as usize; format!( "{index:04}: '{}' (length: {})", @@ -714,7 +708,9 @@ impl CodeBlock { | Instruction::Reserved56 | Instruction::Reserved57 | Instruction::Reserved58 - | Instruction::Reserved59 => unreachable!("Reserved opcodes are unrechable"), + | Instruction::Reserved59 + | Instruction::Reserved60 + | Instruction::Reserved61 => unreachable!("Reserved opcodes are unrechable"), } } } @@ -854,6 +850,7 @@ pub(crate) fn create_function_object( let script_or_module = context.get_active_script_or_module(); let is_async = code.is_async(); + let is_generator = code.is_generator(); let function = OrdinaryFunction::new( code, context.vm.environments.clone(), @@ -861,11 +858,27 @@ pub(crate) fn create_function_object( context.realm().clone(), ); - let data = ObjectData::ordinary_function(function, !is_async); + let data = ObjectData::ordinary_function(function, !is_async && !is_generator); let templates = context.intrinsics().templates(); - let (mut template, storage, constructor_prototype) = if is_async { + let (mut template, storage, constructor_prototype) = if is_generator { + let prototype = JsObject::from_proto_and_data_with_shared_shape( + context.root_shape(), + if is_async { + context.intrinsics().objects().async_generator() + } else { + context.intrinsics().objects().generator() + }, + ObjectData::ordinary(), + ); + + ( + templates.function_with_prototype_without_proto().clone(), + vec![length, name, prototype.into()], + None, + ) + } else if is_async { ( templates.function_without_proto().clone(), vec![length, name], @@ -902,7 +915,6 @@ pub(crate) fn create_function_object( /// with all the properties and prototype set. pub(crate) fn create_function_object_fast( code: Gc, - method: bool, context: &mut Context<'_>, ) -> JsObject { let _timer = Profiler::global().start_event("create_function_object_fast", "vm"); @@ -913,7 +925,8 @@ pub(crate) fn create_function_object_fast( let script_or_module = context.get_active_script_or_module(); let is_async = code.is_async(); - let is_arrow = code.is_arrow(); + let is_generator = code.is_generator(); + let has_prototype_property = code.has_prototype_property(); let function = OrdinaryFunction::new( code, context.vm.environments.clone(), @@ -921,15 +934,35 @@ pub(crate) fn create_function_object_fast( context.realm().clone(), ); - let data = ObjectData::ordinary_function(function, !method && !is_arrow && !is_async); + let data = ObjectData::ordinary_function( + function, + has_prototype_property && !is_async && !is_generator, + ); - if is_async { + if is_generator { + let prototype = JsObject::from_proto_and_data_with_shared_shape( + context.root_shape(), + if is_async { + context.intrinsics().objects().async_generator() + } else { + context.intrinsics().objects().generator() + }, + ObjectData::ordinary(), + ); + let template = if is_async { + context.intrinsics().templates().async_generator_function() + } else { + context.intrinsics().templates().generator_function() + }; + + template.create(data, vec![length, name, prototype.into()]) + } else if is_async { context .intrinsics() .templates() .async_function() .create(data, vec![length, name]) - } else if is_arrow || method { + } else if !has_prototype_property { context .intrinsics() .templates() @@ -953,98 +986,3 @@ pub(crate) fn create_function_object_fast( constructor } } - -/// Creates a new generator function object. -pub(crate) fn create_generator_function_object( - code: Gc, - prototype: Option, - context: &mut Context<'_>, -) -> JsObject { - let is_async = code.is_async(); - let function_prototype = if let Some(prototype) = prototype { - prototype - } else if is_async { - context - .intrinsics() - .constructors() - .async_generator_function() - .prototype() - } else { - context - .intrinsics() - .constructors() - .generator_function() - .prototype() - }; - - let name_property = PropertyDescriptor::builder() - .value(code.name().clone()) - .writable(false) - .enumerable(false) - .configurable(true) - .build(); - - let length_property = PropertyDescriptor::builder() - .value(code.length) - .writable(false) - .enumerable(false) - .configurable(true) - .build(); - - let prototype = JsObject::from_proto_and_data_with_shared_shape( - context.root_shape(), - if is_async { - context.intrinsics().objects().async_generator() - } else { - context.intrinsics().objects().generator() - }, - ObjectData::ordinary(), - ); - - let script_or_module = context.get_active_script_or_module(); - - let constructor = if is_async { - let function = OrdinaryFunction::new( - code, - context.vm.environments.clone(), - script_or_module, - context.realm().clone(), - ); - JsObject::from_proto_and_data_with_shared_shape( - context.root_shape(), - function_prototype, - ObjectData::async_generator_function(function), - ) - } else { - let function = OrdinaryFunction::new( - code, - context.vm.environments.clone(), - script_or_module, - context.realm().clone(), - ); - JsObject::from_proto_and_data_with_shared_shape( - context.root_shape(), - function_prototype, - ObjectData::generator_function(function), - ) - }; - - let prototype_property = PropertyDescriptor::builder() - .value(prototype) - .writable(true) - .enumerable(false) - .configurable(false) - .build(); - - constructor - .define_property_or_throw(PROTOTYPE, prototype_property, context) - .expect("failed to define the prototype property of the generator function"); - constructor - .define_property_or_throw(utf16!("name"), name_property, context) - .expect("failed to define the name property of the generator function"); - constructor - .define_property_or_throw(utf16!("length"), length_property, context) - .expect("failed to define the length property of the generator function"); - - constructor -} diff --git a/boa_engine/src/vm/flowgraph/mod.rs b/boa_engine/src/vm/flowgraph/mod.rs index e732dce3b3..5a8db1a002 100644 --- a/boa_engine/src/vm/flowgraph/mod.rs +++ b/boa_engine/src/vm/flowgraph/mod.rs @@ -242,11 +242,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::GetArrowFunction { .. } | Instruction::GetFunction { .. } => { - graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); - graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); - } - Instruction::GetGenerator { .. } => { + Instruction::GetFunction { .. } => { graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); } @@ -522,7 +518,9 @@ impl CodeBlock { | Instruction::Reserved56 | Instruction::Reserved57 | Instruction::Reserved58 - | Instruction::Reserved59 => unreachable!("Reserved opcodes are unrechable"), + | Instruction::Reserved59 + | Instruction::Reserved60 + | Instruction::Reserved61 => unreachable!("Reserved opcodes are unrechable"), } } diff --git a/boa_engine/src/vm/mod.rs b/boa_engine/src/vm/mod.rs index 06f0555e5c..f5867ceb62 100644 --- a/boa_engine/src/vm/mod.rs +++ b/boa_engine/src/vm/mod.rs @@ -40,8 +40,7 @@ pub use { pub(crate) use { call_frame::CallFrameFlags, code_block::{ - create_function_object, create_function_object_fast, create_generator_function_object, - CodeBlockFlags, Constant, Handler, + create_function_object, create_function_object_fast, CodeBlockFlags, Constant, Handler, }, completion_record::CompletionRecord, opcode::BindingOpcode, diff --git a/boa_engine/src/vm/opcode/get/function.rs b/boa_engine/src/vm/opcode/get/function.rs index 498d8f45a8..c84b13371a 100644 --- a/boa_engine/src/vm/opcode/get/function.rs +++ b/boa_engine/src/vm/opcode/get/function.rs @@ -3,44 +3,6 @@ use crate::{ Context, JsResult, }; -/// `GetArrowFunction` implements the Opcode Operation for `Opcode::GetArrowFunction` -/// -/// Operation: -/// - Get arrow function from the pre-compiled inner functions. -#[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().constant_function(index); - let function = create_function_object_fast(code, false, context); - context.vm.push(function); - Ok(CompletionType::Normal) - } -} - -impl Operation for GetArrowFunction { - const NAME: &'static str = "GetArrowFunction"; - const INSTRUCTION: &'static str = "INST - GetArrowFunction"; - const COST: u8 = 3; - - 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) - } -} - /// `GetFunction` implements the Opcode Operation for `Opcode::GetFunction` /// /// Operation: @@ -50,13 +12,9 @@ pub(crate) struct GetFunction; impl GetFunction { #[allow(clippy::unnecessary_wraps)] - fn operation( - context: &mut Context<'_>, - index: usize, - method: bool, - ) -> JsResult { + fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let code = context.vm.frame().code_block().constant_function(index); - let function = create_function_object_fast(code, method, context); + let function = create_function_object_fast(code, context); context.vm.push(function); Ok(CompletionType::Normal) } @@ -69,19 +27,16 @@ impl Operation for GetFunction { fn execute(context: &mut Context<'_>) -> JsResult { let index = context.vm.read::() as usize; - let method = context.vm.read::() != 0; - Self::operation(context, index, method) + Self::operation(context, index) } 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) + Self::operation(context, index) } 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) + Self::operation(context, index) } } diff --git a/boa_engine/src/vm/opcode/get/generator.rs b/boa_engine/src/vm/opcode/get/generator.rs deleted file mode 100644 index 54ef24492b..0000000000 --- a/boa_engine/src/vm/opcode/get/generator.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{ - vm::{code_block::create_generator_function_object, opcode::Operation, CompletionType}, - Context, JsResult, -}; - -/// `GetGenerator` implements the Opcode Operation for `Opcode::GetGenerator` -/// -/// Operation: -/// - Get generator function from the pre-compiled inner functions. -#[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().constant_function(index); - let function = create_generator_function_object(code, None, context); - context.vm.push(function); - Ok(CompletionType::Normal) - } -} - -impl Operation for GetGenerator { - const NAME: &'static str = "GetGenerator"; - const INSTRUCTION: &'static str = "INST - GetGenerator"; - const COST: u8 = 3; - - 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/mod.rs b/boa_engine/src/vm/opcode/get/mod.rs index 69a67d7a58..3048d3b74c 100644 --- a/boa_engine/src/vm/opcode/get/mod.rs +++ b/boa_engine/src/vm/opcode/get/mod.rs @@ -1,13 +1,11 @@ pub(crate) mod argument; pub(crate) mod function; -pub(crate) mod generator; pub(crate) mod name; pub(crate) mod private; pub(crate) mod property; pub(crate) use argument::*; pub(crate) use function::*; -pub(crate) use generator::*; pub(crate) use name::*; pub(crate) use private::*; pub(crate) use property::*; diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index 97a2612798..cc2dcbd4dc 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -1669,26 +1669,12 @@ generate_opcodes! { /// Stack: `value` **=>** Default { address: u32 }, - /// Get arrow function from the pre-compiled inner functions. - /// - /// Operands: index: `u32` - /// - /// Stack: **=>** func - GetArrowFunction { index: VaryingOperand }, - /// Get function from the pre-compiled inner functions. /// - /// Operands: index: `VaryingOperand`, is_method: `u8` - /// - /// Stack: **=>** func - GetFunction { index: VaryingOperand, method: bool }, - - /// Get generator function from the pre-compiled inner functions. - /// - /// Operands: index: `VaryingOperand`, + /// Operands: index: `VaryingOperand` /// /// Stack: **=>** func - GetGenerator { index: VaryingOperand }, + GetFunction { index: VaryingOperand }, /// Call a function named "eval". /// @@ -2206,6 +2192,10 @@ generate_opcodes! { Reserved58 => Reserved, /// Reserved [`Opcode`]. Reserved59 => Reserved, + /// Reserved [`Opcode`]. + Reserved60 => Reserved, + /// Reserved [`Opcode`]. + Reserved61 => Reserved, } /// Specific opcodes for bindings.