Skip to content

Commit

Permalink
Move FunctionKind to CodeBlock (#3440)
Browse files Browse the repository at this point in the history
* Move `FunctionKind` flag to CodeBlock

* Add `IS_ARROW` flag to codeblock

* Remove GetAsyncArrowFunction and GetFunctionAsync opcodes

* Remove GetGeneratorAsync opcode
  • Loading branch information
HalidOdat authored Oct 30, 2023
1 parent 4b8ca76 commit b4644a5
Show file tree
Hide file tree
Showing 16 changed files with 160 additions and 411 deletions.
142 changes: 35 additions & 107 deletions boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use boa_gc::{self, custom_trace, Finalize, Gc, Trace};
use boa_interner::Sym;
use boa_parser::{Parser, Source};
use boa_profiler::Profiler;
use std::{fmt, io::Read};
use std::io::Read;
use thin_vec::ThinVec;

pub(crate) mod arguments;
Expand Down Expand Up @@ -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.
///
/// `FunctionBody` is specific to this interpreter, it will either be Rust code or JavaScript code
Expand All @@ -228,11 +166,31 @@ pub struct OrdinaryFunction {
/// The [`Realm`] the function is defined in.
pub(crate) realm: Realm,

/// The kind of ordinary function.
pub(crate) kind: FunctionKind,
/// The `[[Fields]]` internal slot.
fields: ThinVec<ClassFieldDefinition>,

/// The `[[PrivateMethods]]` internal slot.
private_methods: ThinVec<(PrivateName, PrivateElement)>,
}

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.
#[must_use]
pub fn codeblock(&self) -> &CodeBlock {
Expand Down Expand Up @@ -266,47 +224,27 @@ impl OrdinaryFunction {

/// Returns the values of the `[[Fields]]` internal slot.
pub(crate) fn get_fields(&self) -> &[ClassFieldDefinition] {
if let FunctionKind::Ordinary { fields, .. } = &self.kind {
fields
} else {
&[]
}
&self.fields
}

/// Pushes a value to the `[[Fields]]` internal slot if present.
pub(crate) fn push_field(&mut self, key: PropertyKey, value: JsFunction) {
if let FunctionKind::Ordinary { fields, .. } = &mut self.kind {
fields.push(ClassFieldDefinition::Public(key, value));
}
self.fields.push(ClassFieldDefinition::Public(key, value));
}

/// Pushes a private value to the `[[Fields]]` internal slot if present.
pub(crate) fn push_field_private(&mut self, name: PrivateName, value: JsFunction) {
if let FunctionKind::Ordinary { fields, .. } = &mut self.kind {
fields.push(ClassFieldDefinition::Private(name, value));
}
self.fields.push(ClassFieldDefinition::Private(name, value));
}

/// Returns the values of the `[[PrivateMethods]]` internal slot.
pub(crate) fn get_private_methods(&self) -> &[(PrivateName, PrivateElement)] {
if let FunctionKind::Ordinary {
private_methods, ..
} = &self.kind
{
private_methods
} else {
&[]
}
&self.private_methods
}

/// Pushes a private method to the `[[PrivateMethods]]` internal slot if present.
pub(crate) fn push_private_method(&mut self, name: PrivateName, method: PrivateElement) {
if let FunctionKind::Ordinary {
private_methods, ..
} = &mut self.kind
{
private_methods.push((name, method));
}
self.private_methods.push((name, method));
}

/// Gets the `Realm` from where this function originates.
Expand All @@ -315,14 +253,9 @@ impl OrdinaryFunction {
&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 warning on line 256 in boa_engine/src/builtins/function/mod.rs

View workflow job for this annotation

GitHub Actions / Upload docs and run benchmarks

unresolved link to `FunctionKind::Ordinary`
pub(crate) const fn is_ordinary(&self) -> bool {
matches!(self.kind(), FunctionKind::Ordinary { .. })
pub(crate) fn is_ordinary(&self) -> bool {
self.code.is_ordinary()
}
}

Expand Down Expand Up @@ -633,9 +566,9 @@ impl BuiltInFunctionObject {
let environments = context.vm.environments.pop_to_global();

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 {
crate::vm::create_function_object(code, r#async, prototype, context)
crate::vm::create_function_object(code, prototype, context)
};

context.vm.environments.extend(environments);
Expand All @@ -655,12 +588,8 @@ impl BuiltInFunctionObject {
);

let environments = context.vm.environments.pop_to_global();
let function_object = crate::vm::create_generator_function_object(
code,
r#async,
Some(prototype),
context,
);
let function_object =
crate::vm::create_generator_function_object(code, Some(prototype), context);
context.vm.environments.extend(environments);

Ok(function_object)
Expand All @@ -677,8 +606,7 @@ impl BuiltInFunctionObject {
);

let environments = context.vm.environments.pop_to_global();
let function_object =
crate::vm::create_function_object(code, r#async, prototype, context);
let function_object = crate::vm::create_function_object(code, prototype, context);
context.vm.environments.extend(environments);

Ok(function_object)
Expand Down
19 changes: 6 additions & 13 deletions boa_engine/src/bytecompiler/declarations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,9 @@ impl ByteCompiler<'_, '_> {

// b. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv.
let function = if generator {
create_generator_function_object(code, r#async, None, self.context)
create_generator_function_object(code, None, self.context)
} 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).
Expand Down Expand Up @@ -737,9 +737,9 @@ impl ByteCompiler<'_, '_> {

// b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv.
let function = if generator {
create_generator_function_object(code, r#async, None, self.context)
create_generator_function_object(code, None, self.context)
} 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).
Expand All @@ -750,15 +750,8 @@ impl ByteCompiler<'_, '_> {
else {
// b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv.
let index = self.push_function_to_constants(code);
if r#async && generator {
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator {
if generator {
self.emit_with_varying_operand(Opcode::GetGenerator, index);
} else if r#async {
self.emit(
Opcode::GetFunctionAsync,
&[Operand::Varying(index), Operand::Bool(false)],
);
} else {
self.emit(
Opcode::GetFunction,
Expand Down Expand Up @@ -1033,7 +1026,7 @@ impl ByteCompiler<'_, '_> {
}

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);
}

Expand Down
10 changes: 5 additions & 5 deletions boa_engine/src/bytecompiler/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl ByteCompiler<'_, '_> {
// stack: value

if r#yield.delegate() {
if self.in_async() {
if self.is_async() {
self.emit_opcode(Opcode::GetAsyncIterator);
} else {
self.emit_opcode(Opcode::GetIterator);
Expand All @@ -192,14 +192,14 @@ impl ByteCompiler<'_, '_> {
let (throw_method_undefined, return_method_undefined) =
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::Await);
}

let (return_gen, exit) =
self.emit_opcode_with_two_operands(Opcode::GeneratorDelegateResume);
if self.in_async() {
if self.is_async() {
self.emit_opcode(Opcode::IteratorValue);
self.async_generator_yield();
} else {
Expand All @@ -210,7 +210,7 @@ impl ByteCompiler<'_, '_> {

self.patch_jump(return_gen);
self.patch_jump(return_method_undefined);
if self.in_async() {
if self.is_async() {
self.emit_opcode(Opcode::Await);
self.emit_opcode(Opcode::Pop);
}
Expand All @@ -219,7 +219,7 @@ impl ByteCompiler<'_, '_> {
self.r#return(true);

self.patch_jump(throw_method_undefined);
self.iterator_close(self.in_async());
self.iterator_close(self.is_async());
self.emit_opcode(Opcode::Throw);

self.patch_jump(exit);
Expand Down
17 changes: 12 additions & 5 deletions boa_engine/src/bytecompiler/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,15 @@ impl FunctionCompiler {
context,
);
compiler.length = length;
compiler.in_async = self.r#async;
compiler.in_generator = self.generator;
compiler
.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 {
compiler.this_mode = ThisMode::Lexical;
Expand All @@ -125,7 +132,7 @@ impl FunctionCompiler {
// `FunctionDeclarationInstantiation` (so they are propagated).
//
// 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%).
//
// Note: If the promise capability is already set, then we do nothing.
Expand Down Expand Up @@ -154,10 +161,10 @@ impl FunctionCompiler {
// - 27.6.3.2 AsyncGeneratorStart ( generator, generatorBody ): <https://tc39.es/ecma262/#sec-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());

if compiler.in_async() {
if compiler.is_async() {
// Patched in `ByteCompiler::finish()`.
compiler.async_handler = Some(compiler.push_handler());
}
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/bytecompiler/jump_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl JumpRecord {
compiler.emit_opcode(Opcode::SetReturnValue);
}

match (compiler.in_async(), compiler.in_generator()) {
match (compiler.is_async(), compiler.is_generator()) {
// Taken from:
// - 27.6.3.2 AsyncGeneratorStart ( generator, generatorBody ): https://tc39.es/ecma262/#sec-asyncgeneratorstart
//
Expand Down
Loading

0 comments on commit b4644a5

Please sign in to comment.