Browse Source

Move `FunctionKind` to `CodeBlock` (#3440)

* Move `FunctionKind` flag to CodeBlock

* Add `IS_ARROW` flag to codeblock

* Remove GetAsyncArrowFunction and GetFunctionAsync opcodes

* Remove GetGeneratorAsync opcode
pull/3441/head
Haled Odat 1 year ago committed by GitHub
parent
commit
b4644a5b87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 142
      boa_engine/src/builtins/function/mod.rs
  2. 19
      boa_engine/src/bytecompiler/declarations.rs
  3. 10
      boa_engine/src/bytecompiler/expression/mod.rs
  4. 17
      boa_engine/src/bytecompiler/function.rs
  5. 2
      boa_engine/src/bytecompiler/jump_control.rs
  6. 57
      boa_engine/src/bytecompiler/mod.rs
  7. 2
      boa_engine/src/bytecompiler/statement/mod.rs
  8. 8
      boa_engine/src/bytecompiler/statement/try.rs
  9. 4
      boa_engine/src/bytecompiler/utils.rs
  10. 8
      boa_engine/src/module/source.rs
  11. 2
      boa_engine/src/object/mod.rs
  12. 130
      boa_engine/src/vm/code_block.rs
  13. 12
      boa_engine/src/vm/flowgraph/mod.rs
  14. 87
      boa_engine/src/vm/opcode/get/function.rs
  15. 40
      boa_engine/src/vm/opcode/get/generator.rs
  16. 27
      boa_engine/src/vm/opcode/mod.rs

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

@ -39,7 +39,7 @@ use boa_gc::{self, custom_trace, Finalize, Gc, Trace};
use boa_interner::Sym; use boa_interner::Sym;
use boa_parser::{Parser, Source}; use boa_parser::{Parser, Source};
use boa_profiler::Profiler; use boa_profiler::Profiler;
use std::{fmt, io::Read}; use std::io::Read;
use thin_vec::ThinVec; use thin_vec::ThinVec;
pub(crate) mod arguments; pub(crate) mod arguments;
@ -143,68 +143,6 @@ unsafe impl Trace for ClassFieldDefinition {
}} }}
} }
#[derive(Finalize)]
pub(crate) enum FunctionKind {
/// A bytecode function.
Ordinary {
/// The `[[Fields]]` internal slot.
fields: ThinVec<ClassFieldDefinition>,
/// The `[[PrivateMethods]]` internal slot.
private_methods: ThinVec<(PrivateName, PrivateElement)>,
},
/// A bytecode async function.
Async,
/// A bytecode generator function.
Generator,
/// A bytecode async generator function.
AsyncGenerator,
}
impl fmt::Debug for FunctionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Ordinary { .. } => f
.debug_struct("FunctionKind::Ordinary")
.finish_non_exhaustive(),
Self::Async { .. } => f
.debug_struct("FunctionKind::Async")
.finish_non_exhaustive(),
Self::Generator { .. } => f
.debug_struct("FunctionKind::Generator")
.finish_non_exhaustive(),
Self::AsyncGenerator { .. } => f
.debug_struct("FunctionKind::AsyncGenerator")
.finish_non_exhaustive(),
}
}
}
unsafe impl Trace for FunctionKind {
custom_trace! {this, {
match this {
Self::Ordinary {
fields,
private_methods,
..
} => {
for elem in fields {
mark(elem);
}
for (_, elem) in private_methods {
mark(elem);
}
}
Self::Async
| Self::Generator
| Self::AsyncGenerator => {}
}
}}
}
/// Boa representation of a JavaScript Function Object. /// Boa representation of a JavaScript Function Object.
/// ///
/// `FunctionBody` is specific to this interpreter, it will either be Rust code or JavaScript code /// `FunctionBody` is specific to this interpreter, it will either be Rust code or JavaScript code
@ -228,11 +166,31 @@ pub struct OrdinaryFunction {
/// The [`Realm`] the function is defined in. /// The [`Realm`] the function is defined in.
pub(crate) realm: Realm, pub(crate) realm: Realm,
/// The kind of ordinary function. /// The `[[Fields]]` internal slot.
pub(crate) kind: FunctionKind, fields: ThinVec<ClassFieldDefinition>,
/// The `[[PrivateMethods]]` internal slot.
private_methods: ThinVec<(PrivateName, PrivateElement)>,
} }
impl OrdinaryFunction { impl OrdinaryFunction {
pub(crate) fn new(
code: Gc<CodeBlock>,
environments: EnvironmentStack,
script_or_module: Option<ActiveRunnable>,
realm: Realm,
) -> Self {
Self {
code,
environments,
home_object: None,
script_or_module,
realm,
fields: ThinVec::default(),
private_methods: ThinVec::default(),
}
}
/// Returns the codeblock of the function. /// Returns the codeblock of the function.
#[must_use] #[must_use]
pub fn codeblock(&self) -> &CodeBlock { pub fn codeblock(&self) -> &CodeBlock {
@ -266,47 +224,27 @@ impl OrdinaryFunction {
/// Returns the values of the `[[Fields]]` internal slot. /// Returns the values of the `[[Fields]]` internal slot.
pub(crate) fn get_fields(&self) -> &[ClassFieldDefinition] { pub(crate) fn get_fields(&self) -> &[ClassFieldDefinition] {
if let FunctionKind::Ordinary { fields, .. } = &self.kind { &self.fields
fields
} else {
&[]
}
} }
/// Pushes a value to the `[[Fields]]` internal slot if present. /// Pushes a value to the `[[Fields]]` internal slot if present.
pub(crate) fn push_field(&mut self, key: PropertyKey, value: JsFunction) { pub(crate) fn push_field(&mut self, key: PropertyKey, value: JsFunction) {
if let FunctionKind::Ordinary { fields, .. } = &mut self.kind { self.fields.push(ClassFieldDefinition::Public(key, value));
fields.push(ClassFieldDefinition::Public(key, value));
}
} }
/// Pushes a private value to the `[[Fields]]` internal slot if present. /// Pushes a private value to the `[[Fields]]` internal slot if present.
pub(crate) fn push_field_private(&mut self, name: PrivateName, value: JsFunction) { pub(crate) fn push_field_private(&mut self, name: PrivateName, value: JsFunction) {
if let FunctionKind::Ordinary { fields, .. } = &mut self.kind { self.fields.push(ClassFieldDefinition::Private(name, value));
fields.push(ClassFieldDefinition::Private(name, value));
}
} }
/// Returns the values of the `[[PrivateMethods]]` internal slot. /// Returns the values of the `[[PrivateMethods]]` internal slot.
pub(crate) fn get_private_methods(&self) -> &[(PrivateName, PrivateElement)] { pub(crate) fn get_private_methods(&self) -> &[(PrivateName, PrivateElement)] {
if let FunctionKind::Ordinary { &self.private_methods
private_methods, ..
} = &self.kind
{
private_methods
} else {
&[]
}
} }
/// Pushes a private method to the `[[PrivateMethods]]` internal slot if present. /// Pushes a private method to the `[[PrivateMethods]]` internal slot if present.
pub(crate) fn push_private_method(&mut self, name: PrivateName, method: PrivateElement) { pub(crate) fn push_private_method(&mut self, name: PrivateName, method: PrivateElement) {
if let FunctionKind::Ordinary { self.private_methods.push((name, method));
private_methods, ..
} = &mut self.kind
{
private_methods.push((name, method));
}
} }
/// Gets the `Realm` from where this function originates. /// Gets the `Realm` from where this function originates.
@ -315,14 +253,9 @@ impl OrdinaryFunction {
&self.realm &self.realm
} }
/// Gets a reference to the [`FunctionKind`] of the `Function`.
pub(crate) const fn kind(&self) -> &FunctionKind {
&self.kind
}
/// Check if function is [`FunctionKind::Ordinary`]. /// Check if function is [`FunctionKind::Ordinary`].
pub(crate) const fn is_ordinary(&self) -> bool { pub(crate) fn is_ordinary(&self) -> bool {
matches!(self.kind(), FunctionKind::Ordinary { .. }) self.code.is_ordinary()
} }
} }
@ -633,9 +566,9 @@ impl BuiltInFunctionObject {
let environments = context.vm.environments.pop_to_global(); let environments = context.vm.environments.pop_to_global();
let function_object = if generator { let function_object = if generator {
crate::vm::create_generator_function_object(code, r#async, Some(prototype), context) crate::vm::create_generator_function_object(code, Some(prototype), context)
} else { } else {
crate::vm::create_function_object(code, r#async, prototype, context) crate::vm::create_function_object(code, prototype, context)
}; };
context.vm.environments.extend(environments); context.vm.environments.extend(environments);
@ -655,12 +588,8 @@ impl BuiltInFunctionObject {
); );
let environments = context.vm.environments.pop_to_global(); let environments = context.vm.environments.pop_to_global();
let function_object = crate::vm::create_generator_function_object( let function_object =
code, crate::vm::create_generator_function_object(code, Some(prototype), context);
r#async,
Some(prototype),
context,
);
context.vm.environments.extend(environments); context.vm.environments.extend(environments);
Ok(function_object) Ok(function_object)
@ -677,8 +606,7 @@ impl BuiltInFunctionObject {
); );
let environments = context.vm.environments.pop_to_global(); let environments = context.vm.environments.pop_to_global();
let function_object = let function_object = crate::vm::create_function_object(code, prototype, context);
crate::vm::create_function_object(code, r#async, prototype, context);
context.vm.environments.extend(environments); context.vm.environments.extend(environments);
Ok(function_object) Ok(function_object)

19
boa_engine/src/bytecompiler/declarations.rs

@ -286,9 +286,9 @@ impl ByteCompiler<'_, '_> {
// b. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv. // b. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv.
let function = if generator { let function = if generator {
create_generator_function_object(code, r#async, None, self.context) create_generator_function_object(code, None, self.context)
} else { } else {
create_function_object_fast(code, r#async, false, false, self.context) create_function_object_fast(code, false, self.context)
}; };
// c. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false). // c. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false).
@ -737,9 +737,9 @@ impl ByteCompiler<'_, '_> {
// b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv. // b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv.
let function = if generator { let function = if generator {
create_generator_function_object(code, r#async, None, self.context) create_generator_function_object(code, None, self.context)
} else { } else {
create_function_object_fast(code, r#async, false, false, self.context) create_function_object_fast(code, false, self.context)
}; };
// i. Perform ? varEnv.CreateGlobalFunctionBinding(fn, fo, true). // i. Perform ? varEnv.CreateGlobalFunctionBinding(fn, fo, true).
@ -750,15 +750,8 @@ impl ByteCompiler<'_, '_> {
else { else {
// b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv. // b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv.
let index = self.push_function_to_constants(code); let index = self.push_function_to_constants(code);
if r#async && generator { if generator {
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator {
self.emit_with_varying_operand(Opcode::GetGenerator, index); self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async {
self.emit(
Opcode::GetFunctionAsync,
&[Operand::Varying(index), Operand::Bool(false)],
);
} else { } else {
self.emit( self.emit(
Opcode::GetFunction, Opcode::GetFunction,
@ -1033,7 +1026,7 @@ impl ByteCompiler<'_, '_> {
} }
if generator { if generator {
self.emit(Opcode::Generator, &[Operand::Bool(self.in_async())]); self.emit(Opcode::Generator, &[Operand::Bool(self.is_async())]);
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }

10
boa_engine/src/bytecompiler/expression/mod.rs

@ -175,7 +175,7 @@ impl ByteCompiler<'_, '_> {
// stack: value // stack: value
if r#yield.delegate() { if r#yield.delegate() {
if self.in_async() { if self.is_async() {
self.emit_opcode(Opcode::GetAsyncIterator); self.emit_opcode(Opcode::GetAsyncIterator);
} else { } else {
self.emit_opcode(Opcode::GetIterator); self.emit_opcode(Opcode::GetIterator);
@ -192,14 +192,14 @@ impl ByteCompiler<'_, '_> {
let (throw_method_undefined, return_method_undefined) = let (throw_method_undefined, return_method_undefined) =
self.emit_opcode_with_two_operands(Opcode::GeneratorDelegateNext); self.emit_opcode_with_two_operands(Opcode::GeneratorDelegateNext);
if self.in_async() { if self.is_async() {
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
self.emit_opcode(Opcode::Await); self.emit_opcode(Opcode::Await);
} }
let (return_gen, exit) = let (return_gen, exit) =
self.emit_opcode_with_two_operands(Opcode::GeneratorDelegateResume); self.emit_opcode_with_two_operands(Opcode::GeneratorDelegateResume);
if self.in_async() { if self.is_async() {
self.emit_opcode(Opcode::IteratorValue); self.emit_opcode(Opcode::IteratorValue);
self.async_generator_yield(); self.async_generator_yield();
} else { } else {
@ -210,7 +210,7 @@ impl ByteCompiler<'_, '_> {
self.patch_jump(return_gen); self.patch_jump(return_gen);
self.patch_jump(return_method_undefined); self.patch_jump(return_method_undefined);
if self.in_async() { if self.is_async() {
self.emit_opcode(Opcode::Await); self.emit_opcode(Opcode::Await);
self.emit_opcode(Opcode::Pop); self.emit_opcode(Opcode::Pop);
} }
@ -219,7 +219,7 @@ impl ByteCompiler<'_, '_> {
self.r#return(true); self.r#return(true);
self.patch_jump(throw_method_undefined); self.patch_jump(throw_method_undefined);
self.iterator_close(self.in_async()); self.iterator_close(self.is_async());
self.emit_opcode(Opcode::Throw); self.emit_opcode(Opcode::Throw);
self.patch_jump(exit); self.patch_jump(exit);

17
boa_engine/src/bytecompiler/function.rs

@ -99,8 +99,15 @@ impl FunctionCompiler {
context, context,
); );
compiler.length = length; compiler.length = length;
compiler.in_async = self.r#async; compiler
compiler.in_generator = self.generator; .code_block_flags
.set(CodeBlockFlags::IS_ASYNC, self.r#async);
compiler
.code_block_flags
.set(CodeBlockFlags::IS_GENERATOR, self.generator);
compiler
.code_block_flags
.set(CodeBlockFlags::IS_ARROW, self.arrow);
if self.arrow { if self.arrow {
compiler.this_mode = ThisMode::Lexical; compiler.this_mode = ThisMode::Lexical;
@ -125,7 +132,7 @@ impl FunctionCompiler {
// `FunctionDeclarationInstantiation` (so they are propagated). // `FunctionDeclarationInstantiation` (so they are propagated).
// //
// See: 15.6.2 Runtime Semantics: EvaluateAsyncGeneratorBody: https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncgeneratorbody // See: 15.6.2 Runtime Semantics: EvaluateAsyncGeneratorBody: https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncgeneratorbody
if compiler.in_async() && !compiler.in_generator() { if compiler.is_async() && !compiler.is_generator() {
// 1. Let promiseCapability be ! NewPromiseCapability(%Promise%). // 1. Let promiseCapability be ! NewPromiseCapability(%Promise%).
// //
// Note: If the promise capability is already set, then we do nothing. // Note: If the promise capability is already set, then we do nothing.
@ -154,10 +161,10 @@ impl FunctionCompiler {
// - 27.6.3.2 AsyncGeneratorStart ( generator, generatorBody ): <https://tc39.es/ecma262/#sec-asyncgeneratorstart> // - 27.6.3.2 AsyncGeneratorStart ( generator, generatorBody ): <https://tc39.es/ecma262/#sec-asyncgeneratorstart>
// //
// Note: We do handle exceptions thrown by generator body in `AsyncGeneratorStart`. // Note: We do handle exceptions thrown by generator body in `AsyncGeneratorStart`.
if compiler.in_generator() { if compiler.is_generator() {
assert!(compiler.async_handler.is_none()); assert!(compiler.async_handler.is_none());
if compiler.in_async() { if compiler.is_async() {
// Patched in `ByteCompiler::finish()`. // Patched in `ByteCompiler::finish()`.
compiler.async_handler = Some(compiler.push_handler()); compiler.async_handler = Some(compiler.push_handler());
} }

2
boa_engine/src/bytecompiler/jump_control.rs

@ -129,7 +129,7 @@ impl JumpRecord {
compiler.emit_opcode(Opcode::SetReturnValue); compiler.emit_opcode(Opcode::SetReturnValue);
} }
match (compiler.in_async(), compiler.in_generator()) { match (compiler.is_async(), compiler.is_generator()) {
// Taken from: // Taken from:
// - 27.6.3.2 AsyncGeneratorStart ( generator, generatorBody ): https://tc39.es/ecma262/#sec-asyncgeneratorstart // - 27.6.3.2 AsyncGeneratorStart ( generator, generatorBody ): https://tc39.es/ecma262/#sec-asyncgeneratorstart
// //

57
boa_engine/src/bytecompiler/mod.rs

@ -261,14 +261,12 @@ pub struct ByteCompiler<'ctx, 'host> {
current_open_environments_count: u32, current_open_environments_count: u32,
current_stack_value_count: u32, current_stack_value_count: u32,
code_block_flags: CodeBlockFlags, pub(crate) code_block_flags: CodeBlockFlags,
handlers: ThinVec<Handler>, handlers: ThinVec<Handler>,
literals_map: FxHashMap<Literal, u32>, literals_map: FxHashMap<Literal, u32>,
names_map: FxHashMap<Identifier, u32>, names_map: FxHashMap<Identifier, u32>,
bindings_map: FxHashMap<BindingLocator, u32>, bindings_map: FxHashMap<BindingLocator, u32>,
jump_info: Vec<JumpControlInfo>, jump_info: Vec<JumpControlInfo>,
pub(crate) in_async: bool,
in_generator: bool,
/// Used to handle exception throws that escape the async function types. /// Used to handle exception throws that escape the async function types.
/// ///
@ -320,8 +318,6 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
names_map: FxHashMap::default(), names_map: FxHashMap::default(),
bindings_map: FxHashMap::default(), bindings_map: FxHashMap::default(),
jump_info: Vec::new(), jump_info: Vec::new(),
in_async: false,
in_generator: false,
async_handler: None, async_handler: None,
json_parse, json_parse,
variable_environment, variable_environment,
@ -337,16 +333,16 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.code_block_flags.contains(CodeBlockFlags::STRICT) self.code_block_flags.contains(CodeBlockFlags::STRICT)
} }
pub(crate) const fn in_async(&self) -> bool { pub(crate) const fn is_async(&self) -> bool {
self.in_async self.code_block_flags.contains(CodeBlockFlags::IS_ASYNC)
} }
pub(crate) const fn in_generator(&self) -> bool { pub(crate) const fn is_generator(&self) -> bool {
self.in_generator self.code_block_flags.contains(CodeBlockFlags::IS_GENERATOR)
} }
pub(crate) const fn in_async_generator(&self) -> bool { pub(crate) const fn is_async_generator(&self) -> bool {
self.in_async() && self.in_generator() self.is_async() && self.is_generator()
} }
pub(crate) fn interner(&self) -> &Interner { pub(crate) fn interner(&self) -> &Interner {
@ -1257,25 +1253,12 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
use_expr: bool, use_expr: bool,
) { ) {
let name = function.name; let name = function.name;
let (generator, r#async, arrow) = ( let (generator, arrow) = (function.kind.is_generator(), function.kind.is_arrow());
function.kind.is_generator(),
function.kind.is_async(),
function.kind.is_arrow(),
);
let index = self.function(function); let index = self.function(function);
if r#async && generator { if generator {
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator {
self.emit_with_varying_operand(Opcode::GetGenerator, index); self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async && arrow {
self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]);
} else if r#async {
self.emit(
Opcode::GetFunctionAsync,
&[Operand::Varying(index), Operand::Bool(false)],
);
} else if arrow { } else if arrow {
self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]); self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]);
} else { } else {
@ -1342,17 +1325,8 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
let index = self.push_function_to_constants(code); let index = self.push_function_to_constants(code);
if r#async && generator { if generator {
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator {
self.emit_with_varying_operand(Opcode::GetGenerator, index); self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async && arrow {
self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]);
} else if r#async {
self.emit(
Opcode::GetFunctionAsync,
&[Operand::Varying(index), Operand::Bool(true)],
);
} else if arrow { } else if arrow {
self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]); self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]);
} else { } else {
@ -1405,17 +1379,8 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
let index = self.push_function_to_constants(code); let index = self.push_function_to_constants(code);
if r#async && generator { if generator {
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator {
self.emit_with_varying_operand(Opcode::GetGenerator, index); self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async && arrow {
self.emit(Opcode::GetAsyncArrowFunction, &[Operand::Varying(index)]);
} else if r#async {
self.emit(
Opcode::GetFunctionAsync,
&[Operand::Varying(index), Operand::Bool(true)],
);
} else if arrow { } else if arrow {
self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]); self.emit(Opcode::GetArrowFunction, &[Operand::Varying(index)]);
} else { } else {

2
boa_engine/src/bytecompiler/statement/mod.rs

@ -65,7 +65,7 @@ impl ByteCompiler<'_, '_> {
Statement::Return(ret) => { Statement::Return(ret) => {
if let Some(expr) = ret.target() { if let Some(expr) = ret.target() {
self.compile_expr(expr, true); self.compile_expr(expr, true);
if self.in_async_generator() { if self.is_async_generator() {
self.emit_opcode(Opcode::Await); self.emit_opcode(Opcode::Await);
self.emit_opcode(Opcode::GeneratorNext); self.emit_opcode(Opcode::GeneratorNext);
} }

8
boa_engine/src/bytecompiler/statement/try.rs

@ -38,7 +38,7 @@ impl ByteCompiler<'_, '_> {
// If it has a finally but no catch and we are in a generator, then we still need it // If it has a finally but no catch and we are in a generator, then we still need it
// to handle `return()` call on generators. // to handle `return()` call on generators.
let catch_handler = if has_finally && (self.in_generator() || has_catch) { let catch_handler = if has_finally && (self.is_generator() || has_catch) {
self.current_stack_value_count += 2; self.current_stack_value_count += 2;
Some(self.push_handler()) Some(self.push_handler())
} else { } else {
@ -50,7 +50,7 @@ impl ByteCompiler<'_, '_> {
self.compile_catch_stmt(catch, has_finally, use_expr); self.compile_catch_stmt(catch, has_finally, use_expr);
} else { } else {
// Note: implicit !has_catch // Note: implicit !has_catch
if self.in_generator() && has_finally { if self.is_generator() && has_finally {
// Is this a generator `return()` empty exception? // Is this a generator `return()` empty exception?
// //
// This is false because when the `Exception` opcode is executed, // This is false because when the `Exception` opcode is executed,
@ -77,7 +77,7 @@ impl ByteCompiler<'_, '_> {
} }
// Note: implicit has_finally // Note: implicit has_finally
if !has_catch && self.in_generator() { if !has_catch && self.is_generator() {
// Is this a generator `return()` empty exception? // Is this a generator `return()` empty exception?
self.emit_opcode(Opcode::PushTrue); self.emit_opcode(Opcode::PushTrue);
} }
@ -153,7 +153,7 @@ impl ByteCompiler<'_, '_> {
if has_catch { if has_catch {
self.emit_opcode(Opcode::ReThrow); self.emit_opcode(Opcode::ReThrow);
} else if self.in_generator() { } else if self.is_generator() {
let is_generator_exit = self.jump_if_true(); let is_generator_exit = self.jump_if_true();
self.emit_opcode(Opcode::Throw); self.emit_opcode(Opcode::Throw);
self.patch_jump(is_generator_exit); self.patch_jump(is_generator_exit);

4
boa_engine/src/bytecompiler/utils.rs

@ -50,7 +50,7 @@ impl ByteCompiler<'_, '_> {
let start = self.next_opcode_location(); let start = self.next_opcode_location();
self.emit_opcode(Opcode::IteratorStackEmpty); self.emit_opcode(Opcode::IteratorStackEmpty);
let empty = self.jump_if_true(); let empty = self.jump_if_true();
self.iterator_close(self.in_async_generator()); self.iterator_close(self.is_async_generator());
self.emit(Opcode::Jump, &[Operand::U32(start)]); self.emit(Opcode::Jump, &[Operand::U32(start)]);
self.patch_jump(empty); self.patch_jump(empty);
} }
@ -65,7 +65,7 @@ impl ByteCompiler<'_, '_> {
/// [yield]: https://tc39.es/ecma262/#sec-yield /// [yield]: https://tc39.es/ecma262/#sec-yield
pub(super) fn r#yield(&mut self) { pub(super) fn r#yield(&mut self) {
// 1. Let generatorKind be GetGeneratorKind(). // 1. Let generatorKind be GetGeneratorKind().
if self.in_async() { if self.is_async() {
// 2. If generatorKind is async, return ? AsyncGeneratorYield(? Await(value)). // 2. If generatorKind is async, return ? AsyncGeneratorYield(? Await(value)).
self.emit_opcode(Opcode::Await); self.emit_opcode(Opcode::Await);
self.emit_opcode(Opcode::GeneratorNext); self.emit_opcode(Opcode::GeneratorNext);

8
boa_engine/src/module/source.rs

@ -29,7 +29,7 @@ use crate::{
realm::Realm, realm::Realm,
vm::{ vm::{
create_function_object_fast, create_generator_function_object, ActiveRunnable, CallFrame, create_function_object_fast, create_generator_function_object, ActiveRunnable, CallFrame,
CallFrameFlags, CodeBlock, CompletionRecord, Opcode, CallFrameFlags, CodeBlock, CodeBlockFlags, CompletionRecord, Opcode,
}, },
Context, JsArgs, JsError, JsNativeError, JsObject, JsResult, JsString, JsValue, NativeFunction, Context, JsArgs, JsError, JsNativeError, JsObject, JsResult, JsString, JsValue, NativeFunction,
}; };
@ -1413,7 +1413,7 @@ impl SourceTextModule {
let mut compiler = let mut compiler =
ByteCompiler::new(Sym::MAIN, true, false, env.clone(), env.clone(), context); ByteCompiler::new(Sym::MAIN, true, false, env.clone(), env.clone(), context);
compiler.in_async = true; compiler.code_block_flags |= CodeBlockFlags::IS_ASYNC;
compiler.async_handler = Some(compiler.push_handler()); compiler.async_handler = Some(compiler.push_handler());
let mut imports = Vec::new(); let mut imports = Vec::new();
@ -1660,9 +1660,9 @@ impl SourceTextModule {
let code = codeblock.constant_function(index as usize); let code = codeblock.constant_function(index as usize);
let function = if kind.is_generator() { let function = if kind.is_generator() {
create_generator_function_object(code, kind.is_async(), None, context) create_generator_function_object(code, None, context)
} else { } else {
create_function_object_fast(code, kind.is_async(), false, false, context) create_function_object_fast(code, false, context)
}; };
context.vm.environments.put_lexical_value( context.vm.environments.put_lexical_value(

2
boa_engine/src/object/mod.rs

@ -244,7 +244,7 @@ unsafe impl Trace for Object {
} }
/// A Private Name. /// A Private Name.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq, Trace, Finalize)]
pub struct PrivateName { pub struct PrivateName {
/// The `[[Description]]` internal slot of the private name. /// The `[[Description]]` internal slot of the private name.
description: JsString, description: JsString,

130
boa_engine/src/vm/code_block.rs

@ -3,7 +3,7 @@
//! This module is for the `CodeBlock` which implements a function representation in the VM //! This module is for the `CodeBlock` which implements a function representation in the VM
use crate::{ use crate::{
builtins::function::{FunctionKind, OrdinaryFunction, ThisMode}, builtins::function::{OrdinaryFunction, ThisMode},
environments::{BindingLocator, CompileTimeEnvironment}, environments::{BindingLocator, CompileTimeEnvironment},
object::{JsObject, ObjectData, PROTOTYPE}, object::{JsObject, ObjectData, PROTOTYPE},
property::PropertyDescriptor, property::PropertyDescriptor,
@ -48,7 +48,7 @@ unsafe impl Readable for f64 {}
bitflags! { bitflags! {
/// Flags for [`CodeBlock`]. /// Flags for [`CodeBlock`].
#[derive(Clone, Copy, Debug, Finalize)] #[derive(Clone, Copy, Debug, Finalize)]
pub(crate) struct CodeBlockFlags: u8 { pub(crate) struct CodeBlockFlags: u16 {
/// Is this function in strict mode. /// Is this function in strict mode.
const STRICT = 0b0000_0001; const STRICT = 0b0000_0001;
@ -72,9 +72,13 @@ bitflags! {
/// `[[ConstructorKind]]` /// `[[ConstructorKind]]`
const IS_DERIVED_CONSTRUCTOR = 0b0100_0000; const IS_DERIVED_CONSTRUCTOR = 0b0100_0000;
const IS_ASYNC = 0b1000_0000;
const IS_GENERATOR = 0b0001_0000_0000;
const IS_ARROW = 0b0010_0000_0000;
/// Trace instruction execution to `stdout`. /// Trace instruction execution to `stdout`.
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
const TRACEABLE = 0b1000_0000; const TRACEABLE = 0b1000_0000_0000_0000;
} }
} }
@ -251,6 +255,26 @@ impl CodeBlock {
.contains(CodeBlockFlags::IS_DERIVED_CONSTRUCTOR) .contains(CodeBlockFlags::IS_DERIVED_CONSTRUCTOR)
} }
/// Returns true if this function an async function.
pub(crate) fn is_async(&self) -> bool {
self.flags.get().contains(CodeBlockFlags::IS_ASYNC)
}
/// Returns true if this function an generator function.
pub(crate) fn is_generator(&self) -> bool {
self.flags.get().contains(CodeBlockFlags::IS_GENERATOR)
}
/// Returns true if this function an async function.
pub(crate) fn is_ordinary(&self) -> bool {
!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)
}
/// Find exception [`Handler`] in the code block given the current program counter (`pc`). /// Find exception [`Handler`] in the code block given the current program counter (`pc`).
#[inline] #[inline]
pub(crate) fn find_handler(&self, pc: u32) -> Option<(usize, &Handler)> { pub(crate) fn find_handler(&self, pc: u32) -> Option<(usize, &Handler)> {
@ -431,8 +455,7 @@ impl CodeBlock {
Instruction::TemplateCreate { count, site } => { Instruction::TemplateCreate { count, site } => {
format!("{}, {site}", count.value()) format!("{}, {site}", count.value())
} }
Instruction::GetFunction { index, method } Instruction::GetFunction { index, method } => {
| Instruction::GetFunctionAsync { index, method } => {
let index = index.value() as usize; let index = index.value() as usize;
format!( format!(
"{index:04}: '{}' (length: {}), method: {method}", "{index:04}: '{}' (length: {}), method: {method}",
@ -440,10 +463,7 @@ impl CodeBlock {
self.constant_function(index).length self.constant_function(index).length
) )
} }
Instruction::GetArrowFunction { index } Instruction::GetArrowFunction { index } | Instruction::GetGenerator { index } => {
| Instruction::GetAsyncArrowFunction { index }
| Instruction::GetGenerator { index }
| Instruction::GetGeneratorAsync { index } => {
let index = index.value() as usize; let index = index.value() as usize;
format!( format!(
"{index:04}: '{}' (length: {})", "{index:04}: '{}' (length: {})",
@ -692,7 +712,10 @@ impl CodeBlock {
| Instruction::Reserved53 | Instruction::Reserved53
| Instruction::Reserved54 | Instruction::Reserved54
| Instruction::Reserved55 | Instruction::Reserved55
| Instruction::Reserved56 => unreachable!("Reserved opcodes are unrechable"), | Instruction::Reserved56
| Instruction::Reserved57
| Instruction::Reserved58
| Instruction::Reserved59 => unreachable!("Reserved opcodes are unrechable"),
} }
} }
} }
@ -821,7 +844,6 @@ impl ToInternedString for CodeBlock {
/// This is slower than direct object template construction that is done in [`create_function_object_fast`]. /// This is slower than direct object template construction that is done in [`create_function_object_fast`].
pub(crate) fn create_function_object( pub(crate) fn create_function_object(
code: Gc<CodeBlock>, code: Gc<CodeBlock>,
r#async: bool,
prototype: JsObject, prototype: JsObject,
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsObject { ) -> JsObject {
@ -832,34 +854,19 @@ pub(crate) fn create_function_object(
let script_or_module = context.get_active_script_or_module(); let script_or_module = context.get_active_script_or_module();
let function = if r#async { let is_async = code.is_async();
OrdinaryFunction { let function = OrdinaryFunction::new(
code, code,
environments: context.vm.environments.clone(), context.vm.environments.clone(),
home_object: None,
script_or_module, script_or_module,
kind: FunctionKind::Async, context.realm().clone(),
realm: context.realm().clone(), );
}
} else {
OrdinaryFunction {
code,
environments: context.vm.environments.clone(),
home_object: None,
script_or_module,
kind: FunctionKind::Ordinary {
fields: ThinVec::new(),
private_methods: ThinVec::new(),
},
realm: context.realm().clone(),
}
};
let data = ObjectData::ordinary_function(function, !r#async); let data = ObjectData::ordinary_function(function, !is_async);
let templates = context.intrinsics().templates(); let templates = context.intrinsics().templates();
let (mut template, storage, constructor_prototype) = if r#async { let (mut template, storage, constructor_prototype) = if is_async {
( (
templates.function_without_proto().clone(), templates.function_without_proto().clone(),
vec![length, name], vec![length, name],
@ -896,8 +903,6 @@ pub(crate) fn create_function_object(
/// with all the properties and prototype set. /// with all the properties and prototype set.
pub(crate) fn create_function_object_fast( pub(crate) fn create_function_object_fast(
code: Gc<CodeBlock>, code: Gc<CodeBlock>,
r#async: bool,
arrow: bool,
method: bool, method: bool,
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsObject { ) -> JsObject {
@ -908,33 +913,24 @@ pub(crate) fn create_function_object_fast(
let script_or_module = context.get_active_script_or_module(); let script_or_module = context.get_active_script_or_module();
let kind = if r#async { let is_async = code.is_async();
FunctionKind::Async let is_arrow = code.is_arrow();
} else { let function = OrdinaryFunction::new(
FunctionKind::Ordinary {
fields: ThinVec::new(),
private_methods: ThinVec::new(),
}
};
let function = OrdinaryFunction {
code, code,
environments: context.vm.environments.clone(), context.vm.environments.clone(),
script_or_module, script_or_module,
home_object: None, context.realm().clone(),
kind, );
realm: context.realm().clone(),
};
let data = ObjectData::ordinary_function(function, !method && !arrow && !r#async); let data = ObjectData::ordinary_function(function, !method && !is_arrow && !is_async);
if r#async { if is_async {
context context
.intrinsics() .intrinsics()
.templates() .templates()
.async_function() .async_function()
.create(data, vec![length, name]) .create(data, vec![length, name])
} else if arrow || method { } else if is_arrow || method {
context context
.intrinsics() .intrinsics()
.templates() .templates()
@ -962,13 +958,13 @@ pub(crate) fn create_function_object_fast(
/// Creates a new generator function object. /// Creates a new generator 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,
prototype: Option<JsObject>, prototype: Option<JsObject>,
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsObject { ) -> JsObject {
let is_async = code.is_async();
let function_prototype = if let Some(prototype) = prototype { let function_prototype = if let Some(prototype) = prototype {
prototype prototype
} else if r#async { } else if is_async {
context context
.intrinsics() .intrinsics()
.constructors() .constructors()
@ -998,7 +994,7 @@ pub(crate) fn create_generator_function_object(
let prototype = JsObject::from_proto_and_data_with_shared_shape( let prototype = JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(), context.root_shape(),
if r#async { if is_async {
context.intrinsics().objects().async_generator() context.intrinsics().objects().async_generator()
} else { } else {
context.intrinsics().objects().generator() context.intrinsics().objects().generator()
@ -1008,29 +1004,25 @@ pub(crate) fn create_generator_function_object(
let script_or_module = context.get_active_script_or_module(); let script_or_module = context.get_active_script_or_module();
let constructor = if r#async { let constructor = if is_async {
let function = OrdinaryFunction { let function = OrdinaryFunction::new(
code, code,
environments: context.vm.environments.clone(), context.vm.environments.clone(),
home_object: None,
script_or_module, script_or_module,
kind: FunctionKind::AsyncGenerator, context.realm().clone(),
realm: context.realm().clone(), );
};
JsObject::from_proto_and_data_with_shared_shape( JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(), context.root_shape(),
function_prototype, function_prototype,
ObjectData::async_generator_function(function), ObjectData::async_generator_function(function),
) )
} else { } else {
let function = OrdinaryFunction { let function = OrdinaryFunction::new(
code, code,
environments: context.vm.environments.clone(), context.vm.environments.clone(),
home_object: None,
script_or_module, script_or_module,
kind: FunctionKind::Generator, context.realm().clone(),
realm: context.realm().clone(), );
};
JsObject::from_proto_and_data_with_shared_shape( JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(), context.root_shape(),
function_prototype, function_prototype,

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

@ -242,14 +242,11 @@ impl CodeBlock {
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None);
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
} }
Instruction::GetArrowFunction { .. } Instruction::GetArrowFunction { .. } | Instruction::GetFunction { .. } => {
| Instruction::GetAsyncArrowFunction { .. }
| Instruction::GetFunction { .. }
| Instruction::GetFunctionAsync { .. } => {
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None);
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
} }
Instruction::GetGenerator { .. } | Instruction::GetGeneratorAsync { .. } => { Instruction::GetGenerator { .. } => {
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None);
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
} }
@ -522,7 +519,10 @@ impl CodeBlock {
| Instruction::Reserved53 | Instruction::Reserved53
| Instruction::Reserved54 | Instruction::Reserved54
| Instruction::Reserved55 | Instruction::Reserved55
| Instruction::Reserved56 => unreachable!("Reserved opcodes are unrechable"), | Instruction::Reserved56
| Instruction::Reserved57
| Instruction::Reserved58
| Instruction::Reserved59 => unreachable!("Reserved opcodes are unrechable"),
} }
} }

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

@ -14,7 +14,7 @@ impl GetArrowFunction {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block().constant_function(index); let code = context.vm.frame().code_block().constant_function(index);
let function = create_function_object_fast(code, false, true, false, context); let function = create_function_object_fast(code, false, context);
context.vm.push(function); context.vm.push(function);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
} }
@ -41,44 +41,6 @@ impl Operation for GetArrowFunction {
} }
} }
/// `GetAsyncArrowFunction` implements the Opcode Operation for `Opcode::GetAsyncArrowFunction`
///
/// Operation:
/// - Get async arrow function from the pre-compiled inner functions.
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetAsyncArrowFunction;
impl GetAsyncArrowFunction {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block().constant_function(index);
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";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}
/// `GetFunction` implements the Opcode Operation for `Opcode::GetFunction` /// `GetFunction` implements the Opcode Operation for `Opcode::GetFunction`
/// ///
/// Operation: /// Operation:
@ -94,7 +56,7 @@ impl GetFunction {
method: bool, method: bool,
) -> JsResult<CompletionType> { ) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block().constant_function(index); let code = context.vm.frame().code_block().constant_function(index);
let function = create_function_object_fast(code, false, false, method, context); let function = create_function_object_fast(code, method, context);
context.vm.push(function); context.vm.push(function);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
} }
@ -123,48 +85,3 @@ impl Operation for GetFunction {
Self::operation(context, index, method) Self::operation(context, index, method)
} }
} }
/// `GetFunctionAsync` implements the Opcode Operation for `Opcode::GetFunctionAsync`
///
/// Operation:
/// - Get async function from the pre-compiled inner functions.
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetFunctionAsync;
impl GetFunctionAsync {
#[allow(clippy::unnecessary_wraps)]
fn operation(
context: &mut Context<'_>,
index: usize,
method: bool,
) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block().constant_function(index);
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";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
let method = context.vm.read::<u8>() != 0;
Self::operation(context, index, method)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
let method = context.vm.read::<u8>() != 0;
Self::operation(context, index, method)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
let method = context.vm.read::<u8>() != 0;
Self::operation(context, index, method)
}
}

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

@ -14,7 +14,7 @@ impl GetGenerator {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block().constant_function(index); let code = context.vm.frame().code_block().constant_function(index);
let function = create_generator_function_object(code, false, None, context); let function = create_generator_function_object(code, None, context);
context.vm.push(function); context.vm.push(function);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
} }
@ -40,41 +40,3 @@ impl Operation for GetGenerator {
Self::operation(context, index) Self::operation(context, index)
} }
} }
/// `GetGeneratorAsync` implements the Opcode Operation for `Opcode::GetGeneratorAsync`
///
/// Operation:
/// - Get async generator function from the pre-compiled inner functions.
#[derive(Debug, Clone, Copy)]
pub(crate) struct GetGeneratorAsync;
impl GetGeneratorAsync {
#[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let code = context.vm.frame().code_block().constant_function(index);
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";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index)
}
fn execute_with_u16_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index)
}
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index)
}
}

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

@ -1676,13 +1676,6 @@ generate_opcodes! {
/// Stack: **=>** func /// Stack: **=>** func
GetArrowFunction { index: VaryingOperand }, GetArrowFunction { index: VaryingOperand },
/// Get async arrow function from the pre-compiled inner functions.
///
/// Operands: index: `VaryingOperand`
///
/// Stack: **=>** func
GetAsyncArrowFunction { index: VaryingOperand },
/// Get function from the pre-compiled inner functions. /// Get function from the pre-compiled inner functions.
/// ///
/// Operands: index: `VaryingOperand`, is_method: `u8` /// Operands: index: `VaryingOperand`, is_method: `u8`
@ -1690,13 +1683,6 @@ generate_opcodes! {
/// Stack: **=>** func /// Stack: **=>** func
GetFunction { index: VaryingOperand, method: bool }, GetFunction { index: VaryingOperand, method: bool },
/// Get async function from the pre-compiled inner functions.
///
/// Operands: index: `VaryingOperand`, method: `u8`
///
/// Stack: **=>** func
GetFunctionAsync { index: VaryingOperand, method: bool },
/// Get generator function from the pre-compiled inner functions. /// Get generator function from the pre-compiled inner functions.
/// ///
/// Operands: index: `VaryingOperand`, /// Operands: index: `VaryingOperand`,
@ -1704,13 +1690,6 @@ generate_opcodes! {
/// Stack: **=>** func /// Stack: **=>** func
GetGenerator { index: VaryingOperand }, GetGenerator { index: VaryingOperand },
/// Get async generator function from the pre-compiled inner functions.
///
/// Operands: index: `VaryingOperand`,
///
/// Stack: **=>** func
GetGeneratorAsync { index: VaryingOperand },
/// Call a function named "eval". /// Call a function named "eval".
/// ///
/// Operands: argument_count: `VaryingOperand` /// Operands: argument_count: `VaryingOperand`
@ -2221,6 +2200,12 @@ generate_opcodes! {
Reserved55 => Reserved, Reserved55 => Reserved,
/// Reserved [`Opcode`]. /// Reserved [`Opcode`].
Reserved56 => Reserved, Reserved56 => Reserved,
/// Reserved [`Opcode`].
Reserved57 => Reserved,
/// Reserved [`Opcode`].
Reserved58 => Reserved,
/// Reserved [`Opcode`].
Reserved59 => Reserved,
} }
/// Specific opcodes for bindings. /// Specific opcodes for bindings.

Loading…
Cancel
Save