Skip to content

Commit

Permalink
Ensure construct always returns an Object
Browse files Browse the repository at this point in the history
  • Loading branch information
jedel1043 committed Jun 20, 2022
1 parent b4e736f commit 946e2f1
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 69 deletions.
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/error/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub(crate) fn create_throw_type_error(context: &mut Context) -> JsObject {
context.intrinsics().constructors().function().prototype(),
ObjectData::function(Function::Native {
function: throw_type_error,
constructor: false,
constructor: None,
}),
);

Expand Down
22 changes: 16 additions & 6 deletions boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
value::IntegerOrInfinity,
Context, JsResult, JsString, JsValue,
};
use boa_gc::{self, Finalize, Gc, Trace};
use boa_gc::{self, unsafe_empty_trace, Finalize, Gc, Trace};
use boa_interner::Sym;
use boa_profiler::Profiler;
use dyn_clone::DynClone;
Expand Down Expand Up @@ -108,12 +108,17 @@ impl ThisMode {
}
}

#[derive(Debug, Trace, Finalize, PartialEq, Clone)]
#[derive(Debug, Finalize, PartialEq, Clone, Copy)]
pub enum ConstructorKind {
Base,
Derived,
}

// SAFETY: `Copy` types are trivially not `Trace`.
unsafe impl Trace for ConstructorKind {
unsafe_empty_trace!();
}

impl ConstructorKind {
/// Returns `true` if the constructor kind is `Base`.
pub fn is_base(&self) -> bool {
Expand Down Expand Up @@ -178,12 +183,12 @@ pub enum Function {
Native {
#[unsafe_ignore_trace]
function: NativeFunctionSignature,
constructor: bool,
constructor: Option<ConstructorKind>,
},
Closure {
#[unsafe_ignore_trace]
function: Box<dyn ClosureFunctionSignature>,
constructor: bool,
constructor: Option<ConstructorKind>,
captures: Captures,
},
Ordinary {
Expand All @@ -205,6 +210,11 @@ impl fmt::Debug for Function {
impl Function {
/// Returns true if the function object is a constructor.
pub fn is_constructor(&self) -> bool {
self.constructor().is_some()
}

/// Returns the constructor kind if the function is constructable, or `None` otherwise.
pub fn constructor(&self) -> Option<ConstructorKind> {
match self {
Self::Native { constructor, .. } | Self::Closure { constructor, .. } => *constructor,
Self::Ordinary { code, .. } | Self::Generator { code, .. } => code.constructor,
Expand Down Expand Up @@ -251,7 +261,7 @@ pub(crate) fn make_builtin_fn<N>(
.prototype(),
ObjectData::function(Function::Native {
function,
constructor: false,
constructor: None,
}),
);
let attribute = PropertyDescriptor::builder()
Expand Down Expand Up @@ -417,7 +427,7 @@ impl BuiltInFunctionObject {
prototype,
ObjectData::function(Function::Native {
function: |_, _, _| Ok(JsValue::undefined()),
constructor: true,
constructor: Some(ConstructorKind::Base),
}),
);

Expand Down
6 changes: 4 additions & 2 deletions boa_engine/src/builtins/generator_function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ use crate::{
};
use boa_profiler::Profiler;

use super::function::ConstructorKind;

/// The internal representation on a `Generator` object.
#[derive(Debug, Clone, Copy)]
pub struct GeneratorFunction;
Expand Down Expand Up @@ -71,7 +73,7 @@ impl BuiltIn for GeneratorFunction {
constructor.borrow_mut().insert("prototype", property);
constructor.borrow_mut().data = ObjectData::function(Function::Native {
function: Self::constructor,
constructor: true,
constructor: Some(ConstructorKind::Base),
});

prototype.set_prototype(Some(
Expand Down Expand Up @@ -124,7 +126,7 @@ impl GeneratorFunction {
prototype,
ObjectData::function(Function::Native {
function: |_, _, _| Ok(JsValue::undefined()),
constructor: true,
constructor: Some(ConstructorKind::Base),
}),
);

Expand Down
26 changes: 20 additions & 6 deletions boa_engine/src/bytecompiler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
builtins::function::ThisMode,
builtins::function::{ConstructorKind, ThisMode},
environments::{BindingLocator, CompileTimeEnvironment},
syntax::ast::{
node::{
Expand Down Expand Up @@ -81,7 +81,7 @@ impl<'b> ByteCompiler<'b> {
#[inline]
pub fn new(name: Sym, strict: bool, context: &'b mut Context) -> Self {
Self {
code_block: CodeBlock::new(name, 0, strict, false),
code_block: CodeBlock::new(name, 0, strict, None),
literals_map: FxHashMap::default(),
names_map: FxHashMap::default(),
bindings_map: FxHashMap::default(),
Expand Down Expand Up @@ -1885,15 +1885,20 @@ impl<'b> ByteCompiler<'b> {
) -> JsResult<Gc<CodeBlock>> {
let strict = strict || body.strict();
let length = parameters.length();
let mut code = CodeBlock::new(name.unwrap_or(Sym::EMPTY_STRING), length, strict, true);
let mut code = CodeBlock::new(
name.unwrap_or(Sym::EMPTY_STRING),
length,
strict,
Some(ConstructorKind::Base),
);

if let FunctionKind::Arrow = kind {
code.constructor = false;
code.constructor = None;
code.this_mode = ThisMode::Lexical;
}

if generator {
code.constructor = false;
code.constructor = None;
}

let mut compiler = ByteCompiler {
Expand Down Expand Up @@ -2494,7 +2499,16 @@ impl<'b> ByteCompiler<'b> {
/// A class declaration binds the resulting class object to it's identifier.
/// A class expression leaves the resulting class object on the stack for following operations.
fn class(&mut self, class: &Class, expression: bool) -> JsResult<()> {
let mut code = CodeBlock::new(class.name(), 0, true, true);
let mut code = CodeBlock::new(
class.name(),
0,
true,
Some(if class.super_ref().is_some() {
ConstructorKind::Derived
} else {
ConstructorKind::Base
}),
);
code.computed_field_names = Some(gc::GcCell::new(vec![]));
let mut compiler = ByteCompiler {
code_block: code,
Expand Down
19 changes: 10 additions & 9 deletions boa_engine/src/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ use crate::{
array_buffer::ArrayBuffer,
function::arguments::Arguments,
function::{
arguments::ParameterMap, BoundFunction, Captures, Function, NativeFunctionSignature,
arguments::ParameterMap, BoundFunction, Captures, ConstructorKind, Function,
NativeFunctionSignature,
},
generator::Generator,
map::map_iterator::MapIterator,
Expand Down Expand Up @@ -1460,7 +1461,7 @@ impl<'context> FunctionBuilder<'context> {
context,
function: Function::Native {
function,
constructor: false,
constructor: None,
},
name: JsString::default(),
length: 0,
Expand All @@ -1477,7 +1478,7 @@ impl<'context> FunctionBuilder<'context> {
context,
function: Function::Closure {
function: Box::new(move |this, args, _, context| function(this, args, context)),
constructor: false,
constructor: None,
captures: Captures::new(()),
},
name: JsString::default(),
Expand Down Expand Up @@ -1511,7 +1512,7 @@ impl<'context> FunctionBuilder<'context> {
})?;
function(this, args, captures, context)
}),
constructor: false,
constructor: None,
captures: Captures::new(captures),
},
name: JsString::default(),
Expand Down Expand Up @@ -1559,7 +1560,7 @@ impl<'context> FunctionBuilder<'context> {
ref mut constructor,
..
} => {
*constructor = yes;
*constructor = yes.then(|| ConstructorKind::Base);
}
Function::Ordinary { .. } | Function::Generator { .. } => {
unreachable!("function must be native or closure");
Expand Down Expand Up @@ -1716,7 +1717,7 @@ pub struct ConstructorBuilder<'context> {
name: JsString,
length: usize,
callable: bool,
constructor: bool,
constructor: Option<ConstructorKind>,
inherit: Option<JsPrototype>,
custom_prototype: Option<JsPrototype>,
}
Expand Down Expand Up @@ -1748,7 +1749,7 @@ impl<'context> ConstructorBuilder<'context> {
length: 0,
name: JsString::default(),
callable: true,
constructor: true,
constructor: Some(ConstructorKind::Base),
inherit: None,
custom_prototype: None,
has_prototype_property: true,
Expand All @@ -1770,7 +1771,7 @@ impl<'context> ConstructorBuilder<'context> {
length: 0,
name: JsString::default(),
callable: true,
constructor: true,
constructor: Some(ConstructorKind::Base),
inherit: None,
custom_prototype: None,
}
Expand Down Expand Up @@ -1967,7 +1968,7 @@ impl<'context> ConstructorBuilder<'context> {
/// Default is `true`
#[inline]
pub fn constructor(&mut self, constructor: bool) -> &mut Self {
self.constructor = constructor;
self.constructor = constructor.then(|| ConstructorKind::Base);
self
}

Expand Down
Loading

0 comments on commit 946e2f1

Please sign in to comment.