Browse Source

Fix remaining object literal tests (#2906)

pull/2910/head
raskad 2 years ago committed by GitHub
parent
commit
484cc16bb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 39
      boa_engine/src/builtins/function/mod.rs
  2. 19
      boa_engine/src/builtins/mod.rs
  3. 8
      boa_engine/src/bytecompiler/declarations.rs
  4. 24
      boa_engine/src/bytecompiler/expression/object_literal.rs
  5. 87
      boa_engine/src/bytecompiler/mod.rs
  6. 20
      boa_engine/src/object/mod.rs
  7. 42
      boa_engine/src/vm/code_block.rs
  8. 16
      boa_engine/src/vm/flowgraph/mod.rs
  9. 6
      boa_engine/src/vm/opcode/get/generator.rs
  10. 4
      boa_engine/src/vm/opcode/mod.rs
  11. 3
      boa_parser/src/parser/expression/assignment/yield.rs
  12. 2
      boa_parser/src/parser/expression/primary/object_initializer/mod.rs

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

@ -292,17 +292,6 @@ pub struct Function {
}
impl Function {
/// Returns true if the function object is a constructor.
pub fn is_constructor(&self) -> bool {
match &self.kind {
FunctionKind::Native { constructor, .. } => constructor.is_some(),
FunctionKind::Generator { .. }
| FunctionKind::AsyncGenerator { .. }
| FunctionKind::Async { .. } => false,
FunctionKind::Ordinary { code, .. } => !(code.this_mode == ThisMode::Lexical),
}
}
/// Returns the codeblock of the function, or `None` if the function is a [`NativeFunction`].
pub fn codeblock(&self) -> Option<&CodeBlock> {
match &self.kind {
@ -725,22 +714,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,
false,
Some(prototype),
context,
)
crate::vm::create_generator_function_object(code, r#async, Some(prototype), context)
} else {
crate::vm::create_function_object(
code,
r#async,
false,
Some(prototype),
false,
context,
)
crate::vm::create_function_object(code, r#async, prototype, context)
};
context.vm.environments.extend(environments);
@ -761,7 +737,6 @@ impl BuiltInFunctionObject {
let function_object = crate::vm::create_generator_function_object(
code,
r#async,
false,
Some(prototype),
context,
);
@ -777,14 +752,8 @@ impl BuiltInFunctionObject {
);
let environments = context.vm.environments.pop_to_global();
let function_object = crate::vm::create_function_object(
code,
r#async,
false,
Some(prototype),
false,
context,
);
let function_object =
crate::vm::create_function_object(code, r#async, prototype, context);
context.vm.environments.extend(environments);
Ok(function_object)

19
boa_engine/src/builtins/mod.rs

@ -538,13 +538,16 @@ impl ApplyToObject for OrdinaryFunction {
impl<S: ApplyToObject + IsConstructor> ApplyToObject for Callable<S> {
fn apply_to(self, object: &mut BuiltInObjectInitializer) {
let function = ObjectData::function(function::Function::new(
function::FunctionKind::Native {
function: NativeFunction::from_fn_ptr(self.function),
constructor: S::IS_CONSTRUCTOR.then_some(function::ConstructorKind::Base),
},
self.realm,
));
let function = ObjectData::function(
function::Function::new(
function::FunctionKind::Native {
function: NativeFunction::from_fn_ptr(self.function),
constructor: S::IS_CONSTRUCTOR.then_some(function::ConstructorKind::Base),
},
self.realm,
),
S::IS_CONSTRUCTOR,
);
object.set_data(function);
object.insert(
utf16!("length"),
@ -922,7 +925,7 @@ impl BuiltInCallable<'_> {
let function = function::Function::new(function, self.realm.clone());
let object = self.realm.intrinsics().templates().function().create(
ObjectData::function(function),
ObjectData::function(function, false),
vec![JsValue::new(self.length), JsValue::new(self.name)],
);

8
boa_engine/src/bytecompiler/declarations.rs

@ -195,7 +195,7 @@ 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, false, None, self.context)
create_generator_function_object(code, r#async, None, self.context)
} else {
create_function_object_fast(code, r#async, false, false, self.context)
};
@ -502,7 +502,7 @@ impl ByteCompiler<'_, '_> {
if var_environment_is_global {
// b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv.
let function = if generator {
create_generator_function_object(code, r#async, false, None, self.context)
create_generator_function_object(code, r#async, None, self.context)
} else {
create_function_object_fast(code, r#async, false, false, self.context)
};
@ -525,7 +525,9 @@ impl ByteCompiler<'_, '_> {
} else {
self.emit(Opcode::GetFunction, &[index]);
}
self.emit_u8(0);
if !generator {
self.emit_u8(0);
}
// i. Let bindingExists be ! varEnv.HasBinding(fn).
let binding_exists = self.has_binding_eval(name, strict);

24
boa_engine/src/bytecompiler/expression/object_literal.rs

@ -46,7 +46,7 @@ impl ByteCompiler<'_, '_> {
PropertyDefinition::MethodDefinition(name, kind) => match kind {
MethodDefinition::Get(expr) => match name {
PropertyName::Literal(name) => {
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertyGetterByName, &[index]);
}
@ -54,7 +54,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(1);
self.emit_opcode(Opcode::SetPropertyGetterByValue);
@ -62,7 +62,7 @@ impl ByteCompiler<'_, '_> {
},
MethodDefinition::Set(expr) => match name {
PropertyName::Literal(name) => {
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::SetPropertySetterByName, &[index]);
}
@ -70,7 +70,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(2);
self.emit_opcode(Opcode::SetPropertySetterByValue);
@ -78,7 +78,7 @@ impl ByteCompiler<'_, '_> {
},
MethodDefinition::Ordinary(expr) => match name {
PropertyName::Literal(name) => {
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[index]);
}
@ -86,7 +86,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(0);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
@ -94,7 +94,7 @@ impl ByteCompiler<'_, '_> {
},
MethodDefinition::Async(expr) => match name {
PropertyName::Literal(name) => {
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[index]);
}
@ -102,7 +102,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(0);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
@ -110,7 +110,7 @@ impl ByteCompiler<'_, '_> {
},
MethodDefinition::Generator(expr) => match name {
PropertyName::Literal(name) => {
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[index]);
}
@ -118,7 +118,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(0);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
@ -126,7 +126,7 @@ impl ByteCompiler<'_, '_> {
},
MethodDefinition::AsyncGenerator(expr) => match name {
PropertyName::Literal(name) => {
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
let index = self.get_or_insert_name((*name).into());
self.emit(Opcode::DefineOwnPropertyByName, &[index]);
}
@ -134,7 +134,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(name_node, true);
self.emit_opcode(Opcode::ToPropertyKey);
self.emit_opcode(Opcode::Dup);
self.function(expr.into(), NodeKind::Expression, true);
self.object_method(expr.into(), NodeKind::Expression, true);
self.emit_opcode(Opcode::SetFunctionName);
self.emit_u8(0);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);

87
boa_engine/src/bytecompiler/mod.rs

@ -1100,7 +1100,88 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
} else {
self.emit(Opcode::GetFunction, &[index]);
}
self.emit_u8(0);
if !generator {
self.emit_u8(0);
}
match node_kind {
NodeKind::Declaration => {
self.emit_binding(
BindingOpcode::InitVar,
name.expect("function declaration must have a name"),
);
}
NodeKind::Expression => {
if !use_expr {
self.emit(Opcode::Pop, &[]);
}
}
}
}
/// Compile an object method AST Node into bytecode.
pub(crate) fn object_method(
&mut self,
function: FunctionSpec<'_>,
node_kind: NodeKind,
use_expr: bool,
) {
let (generator, r#async, arrow) = (
function.is_generator(),
function.is_async(),
function.is_arrow(),
);
let FunctionSpec {
name,
parameters,
body,
has_binding_identifier,
..
} = function;
let binding_identifier = if has_binding_identifier {
if let Some(name) = name {
Some(name.sym())
} else {
Some(Sym::EMPTY_STRING)
}
} else {
None
};
let code = FunctionCompiler::new()
.name(name.map(Identifier::sym))
.generator(generator)
.r#async(r#async)
.strict(self.strict)
.arrow(arrow)
.binding_identifier(binding_identifier)
.compile(
parameters,
body,
self.current_environment.clone(),
self.context,
);
let index = self.functions.len() as u32;
self.functions.push(code);
if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[index]);
} else if generator {
self.emit(Opcode::GetGenerator, &[index]);
} else if r#async && arrow {
self.emit(Opcode::GetAsyncArrowFunction, &[index]);
} else if r#async {
self.emit(Opcode::GetFunctionAsync, &[index]);
} else if arrow {
self.emit(Opcode::GetArrowFunction, &[index]);
} else {
self.emit(Opcode::GetFunction, &[index]);
}
if !generator {
self.emit_u8(1);
}
match node_kind {
NodeKind::Declaration => {
@ -1179,7 +1260,9 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
} else {
self.emit(Opcode::GetFunction, &[index]);
}
self.emit_u8(1);
if !generator {
self.emit_u8(1);
}
match node_kind {
NodeKind::Declaration => {

20
boa_engine/src/object/mod.rs

@ -407,11 +407,7 @@ impl ObjectData {
/// Create the `AsyncGeneratorFunction` object data
pub fn async_generator_function(function: Function) -> Self {
Self {
internal_methods: if function.is_constructor() {
&CONSTRUCTOR_INTERNAL_METHODS
} else {
&FUNCTION_INTERNAL_METHODS
},
internal_methods: &FUNCTION_INTERNAL_METHODS,
kind: ObjectKind::GeneratorFunction(function),
}
}
@ -518,9 +514,9 @@ impl ObjectData {
}
/// Create the `Function` object data
pub fn function(function: Function) -> Self {
pub fn function(function: Function, constructor: bool) -> Self {
Self {
internal_methods: if function.is_constructor() {
internal_methods: if constructor {
&CONSTRUCTOR_INTERNAL_METHODS
} else {
&FUNCTION_INTERNAL_METHODS
@ -552,11 +548,7 @@ impl ObjectData {
/// Create the `GeneratorFunction` object data
pub fn generator_function(function: Function) -> Self {
Self {
internal_methods: if function.is_constructor() {
&CONSTRUCTOR_INTERNAL_METHODS
} else {
&FUNCTION_INTERNAL_METHODS
},
internal_methods: &FUNCTION_INTERNAL_METHODS,
kind: ObjectKind::GeneratorFunction(function),
}
}
@ -1868,7 +1860,7 @@ impl<'ctx, 'host> FunctionObjectBuilder<'ctx, 'host> {
self.context.realm().clone(),
);
let object = self.context.intrinsics().templates().function().create(
ObjectData::function(function),
ObjectData::function(function, self.constructor.is_some()),
vec![self.length.into(), self.name.into()],
);
@ -2303,7 +2295,7 @@ impl<'ctx, 'host> ConstructorBuilder<'ctx, 'host> {
let mut constructor = self.constructor_object;
constructor.insert(utf16!("length"), length);
constructor.insert(utf16!("name"), name);
let data = ObjectData::function(function);
let data = ObjectData::function(function, self.kind.is_some());
constructor.kind = data.kind;

42
boa_engine/src/vm/code_block.rs

@ -313,9 +313,7 @@ impl CodeBlock {
Opcode::GetArrowFunction
| Opcode::GetAsyncArrowFunction
| Opcode::GetFunction
| Opcode::GetFunctionAsync
| Opcode::GetGenerator
| Opcode::GetGeneratorAsync => {
| Opcode::GetFunctionAsync => {
let operand = self.read::<u32>(*pc);
*pc += size_of::<u32>() + size_of::<u8>();
format!(
@ -324,6 +322,14 @@ impl CodeBlock {
self.functions[operand as usize].length
)
}
Opcode::GetGenerator | Opcode::GetGeneratorAsync => {
let operand = self.read::<u32>(*pc);
format!(
"{operand:04}: '{}' (length: {})",
interner.resolve_expect(self.functions[operand as usize].name),
self.functions[operand as usize].length
)
}
Opcode::DefInitArg
| Opcode::DefVar
| Opcode::DefInitVar
@ -582,18 +588,11 @@ impl ToInternedString for CodeBlock {
pub(crate) fn create_function_object(
code: Gc<CodeBlock>,
r#async: bool,
arrow: bool,
prototype: Option<JsObject>,
method: bool,
prototype: JsObject,
context: &mut Context<'_>,
) -> JsObject {
let _timer = Profiler::global().start_event("create_function_object", "vm");
let Some(prototype) = prototype else {
// fast path
return create_function_object_fast(code, r#async, arrow, method, context);
};
let name: JsValue = context
.interner()
.resolve_expect(code.name)
@ -627,11 +626,11 @@ pub(crate) fn create_function_object(
)
};
let data = ObjectData::function(function);
let data = ObjectData::function(function, !r#async);
let templates = context.intrinsics().templates();
let (mut template, storage, constructor_prototype) = if r#async || arrow || method {
let (mut template, storage, constructor_prototype) = if r#async {
(
templates.function_without_proto().clone(),
vec![length, name],
@ -653,12 +652,12 @@ pub(crate) fn create_function_object(
template.set_prototype(prototype);
let contructor = template.create(data, storage);
let constructor = template.create(data, storage);
if let Some(constructor_prototype) = &constructor_prototype {
constructor_prototype.borrow_mut().properties_mut().storage[0] = contructor.clone().into();
constructor_prototype.borrow_mut().properties_mut().storage[0] = constructor.clone().into();
}
contructor
constructor
}
/// Creates a new function object.
@ -704,7 +703,7 @@ pub(crate) fn create_function_object_fast(
let function = Function::new(function, context.realm().clone());
let data = ObjectData::function(function);
let data = ObjectData::function(function, !method && !arrow && !r#async);
if r#async {
context
@ -741,7 +740,6 @@ pub(crate) fn create_function_object_fast(
pub(crate) fn create_generator_function_object(
code: Gc<CodeBlock>,
r#async: bool,
method: bool,
prototype: Option<JsObject>,
context: &mut Context<'_>,
) -> JsObject {
@ -829,11 +827,9 @@ pub(crate) fn create_generator_function_object(
.configurable(false)
.build();
if !method {
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(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");

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

@ -380,9 +380,7 @@ impl CodeBlock {
Opcode::GetArrowFunction
| Opcode::GetAsyncArrowFunction
| Opcode::GetFunction
| Opcode::GetFunctionAsync
| Opcode::GetGenerator
| Opcode::GetGeneratorAsync => {
| Opcode::GetFunctionAsync => {
let operand = self.read::<u32>(pc);
let fn_name = interner
.resolve_expect(self.functions[operand as usize].name)
@ -395,6 +393,18 @@ impl CodeBlock {
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None);
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
}
Opcode::GetGenerator | Opcode::GetGeneratorAsync => {
let operand = self.read::<u32>(pc);
let fn_name = interner
.resolve_expect(self.functions[operand as usize].name)
.to_string();
let label = format!(
"{opcode_str} '{fn_name}' (length: {})",
self.functions[operand as usize].length
);
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None);
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
}
Opcode::DefInitArg
| Opcode::DefVar
| Opcode::DefInitVar

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

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

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

@ -1293,14 +1293,14 @@ generate_impl! {
/// Get generator function from the pre-compiled inner functions.
///
/// Operands: address: `u32`, method: `u8`
/// Operands: address: `u32`,
///
/// Stack: **=>** func
GetGenerator,
/// Get async generator function from the pre-compiled inner functions.
///
/// Operands: address: `u32`, method: `u8`
/// Operands: address: `u32`,
///
/// Stack: **=>** func
GetGeneratorAsync,

3
boa_parser/src/parser/expression/assignment/yield.rs

@ -98,7 +98,8 @@ where
| Keyword::This
| Keyword::Function
| Keyword::Class
| Keyword::Async,
| Keyword::Async
| Keyword::Super,
_,
))
| TokenKind::BooleanLiteral(_)

2
boa_parser/src/parser/expression/primary/object_initializer/mod.rs

@ -583,7 +583,7 @@ where
TokenKind::Punctuator(Punctuator::OpenBracket) => {
cursor.advance(interner);
let node =
AssignmentExpression::new(None, false, self.allow_yield, self.allow_await)
AssignmentExpression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
cursor.expect(Punctuator::CloseBracket, "expected token ']'", interner)?;
return Ok(node.into());

Loading…
Cancel
Save