Skip to content

Commit

Permalink
Unify generator and ordinary function creation (#3441)
Browse files Browse the repository at this point in the history
* Unify generator and ordinary function creation

* Remove GetGenerator opcode

* Remove GetArrowFunction opcode
  • Loading branch information
HalidOdat authored Oct 31, 2023
1 parent cc9b6ba commit 2c12bae
Show file tree
Hide file tree
Showing 15 changed files with 161 additions and 423 deletions.
80 changes: 21 additions & 59 deletions boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -551,66 +551,28 @@ impl BuiltInFunctionObject {
.into());
}

let code = FunctionCompiler::new()
.name(Sym::ANONYMOUS)
.generator(generator)
.r#async(r#async)
.compile(
&parameters,
&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(
&parameters,
&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 )`
Expand Down
25 changes: 5 additions & 20 deletions boa_engine/src/bytecompiler/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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) => {
Expand All @@ -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) => {
Expand Down Expand Up @@ -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);
Expand All @@ -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 {
Expand Down
26 changes: 4 additions & 22 deletions boa_engine/src/bytecompiler/declarations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
14 changes: 11 additions & 3 deletions boa_engine/src/bytecompiler/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub(crate) struct FunctionCompiler {
r#async: bool,
strict: bool,
arrow: bool,
method: bool,
binding_identifier: Option<Sym>,
}

Expand All @@ -32,6 +33,7 @@ impl FunctionCompiler {
r#async: false,
strict: false,
arrow: false,
method: false,
binding_identifier: None,
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
40 changes: 6 additions & 34 deletions boa_engine/src/bytecompiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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,
Expand All @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down
Loading

0 comments on commit 2c12bae

Please sign in to comment.