Skip to content

Commit

Permalink
Merge 5a2e439 into 53e0820
Browse files Browse the repository at this point in the history
  • Loading branch information
jedel1043 authored Apr 6, 2023
2 parents 53e0820 + 5a2e439 commit ed2f008
Show file tree
Hide file tree
Showing 13 changed files with 543 additions and 708 deletions.
14 changes: 8 additions & 6 deletions boa_engine/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@ impl IntrinsicObject for Array {
.name("get [Symbol.species]")
.build();

let values_function =
BuiltInBuilder::with_object(intrinsics, intrinsics.objects().array_prototype_values())
.callable(Self::values)
.name("values")
.build();
let values_function = BuiltInBuilder::with_object(
intrinsics,
intrinsics.objects().array_prototype_values().into(),
)
.callable(Self::values)
.name("values")
.build();

let unscopables_object = Self::unscopables_object();

Expand Down Expand Up @@ -360,7 +362,7 @@ impl Array {
// a. Let thisRealm be the current Realm Record.
// b. Let realmC be ? GetFunctionRealm(C).
// c. If thisRealm and realmC are not the same Realm Record, then
if *c == context.intrinsics().constructors().array().constructor {
if *c == context.intrinsics().constructors().array().constructor() {
// i. If SameValue(C, realmC.[[Intrinsics]].[[%Array%]]) is true, set C to undefined.
// Note: fast path to step 6.
return Self::array_create(length, None, context);
Expand Down
7 changes: 3 additions & 4 deletions boa_engine/src/builtins/error/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ use crate::{
},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
error::JsNativeError,
native_function::NativeFunction,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData, ObjectKind},
property::Attribute,
string::utf16,
Context, JsArgs, JsResult, JsValue,
Context, JsArgs, JsResult, JsValue, NativeFunction,
};
use boa_profiler::Profiler;

Expand Down Expand Up @@ -115,7 +114,7 @@ impl IntrinsicObject for ThrowTypeError {

let mut obj = obj.borrow_mut();

obj.data = ObjectData::function(Function::Native {
*obj.kind_mut() = ObjectKind::Function(Function::Native {
function: NativeFunction::from_fn_ptr(throw_type_error),
constructor: None,
});
Expand Down
206 changes: 143 additions & 63 deletions boa_engine/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ use crate::{
js_string,
native_function::{NativeFunction, NativeFunctionPointer},
object::{
FunctionBinding, JsFunction, JsObject, JsPrototype, ObjectData, CONSTRUCTOR, PROTOTYPE,
FunctionBinding, JsFunction, JsObject, JsPrototype, Object, ObjectData, CONSTRUCTOR,
PROTOTYPE,
},
property::{Attribute, PropertyDescriptor, PropertyKey},
string::utf16,
Expand Down Expand Up @@ -393,6 +394,82 @@ pub(crate) fn set_default_global_bindings(context: &mut Context<'_>) -> JsResult

// === Builder typestate ===

#[derive(Debug)]
enum BuiltInObjectInitializer {
Shared(JsObject),
Unique { object: Object, data: ObjectData },
}

impl BuiltInObjectInitializer {
/// Inserts a new property descriptor into the builtin.
fn insert<K, P>(&mut self, key: K, property: P)
where
K: Into<PropertyKey>,
P: Into<PropertyDescriptor>,
{
match self {
BuiltInObjectInitializer::Shared(obj) => obj.borrow_mut().insert(key, property),
BuiltInObjectInitializer::Unique { object, .. } => object.insert(key, property),
};
}

/// Sets the prototype of the builtin
fn set_prototype(&mut self, prototype: JsObject) {
match self {
BuiltInObjectInitializer::Shared(obj) => {
let mut obj = obj.borrow_mut();
obj.set_prototype(prototype);
}
BuiltInObjectInitializer::Unique { object, .. } => {
object.set_prototype(prototype);
}
}
}

/// Sets the `ObjectData` of the builtin.
///
/// # Panics
///
/// Panics if the builtin is a shared builtin and the data's vtable is not the same as the
/// builtin's vtable.
fn set_data(&mut self, new_data: ObjectData) {
match self {
BuiltInObjectInitializer::Shared(obj) => {
assert!(std::ptr::eq(obj.vtable(), new_data.internal_methods));
*obj.borrow_mut().kind_mut() = new_data.kind;
}
BuiltInObjectInitializer::Unique { ref mut data, .. } => *data = new_data,
}
}

/// Gets a shared object from the builtin, transitioning its state if it's necessary.
fn as_shared(&mut self) -> JsObject {
match std::mem::replace(
self,
BuiltInObjectInitializer::Unique {
object: Object::default(),
data: ObjectData::ordinary(),
},
) {
BuiltInObjectInitializer::Shared(obj) => {
*self = BuiltInObjectInitializer::Shared(obj.clone());
obj
}
BuiltInObjectInitializer::Unique { mut object, data } => {
*object.kind_mut() = data.kind;
let obj = JsObject::from_object_and_vtable(object, data.internal_methods);
*self = BuiltInObjectInitializer::Shared(obj.clone());
obj
}
}
}

/// Converts the builtin into a shared object.
fn into_shared(mut self) -> JsObject {
self.as_shared()
}
}

/// Marker for a constructor function.
struct Constructor {
prototype: JsObject,
Expand Down Expand Up @@ -436,74 +513,75 @@ struct OrdinaryObject;

/// Applies the pending builder data to the object.
trait ApplyToObject {
fn apply_to(self, object: &JsObject);
fn apply_to(self, object: &mut BuiltInObjectInitializer);
}

impl ApplyToObject for Constructor {
fn apply_to(self, object: &JsObject) {
fn apply_to(self, object: &mut BuiltInObjectInitializer) {
object.insert(
PROTOTYPE,
PropertyDescriptor::builder()
.value(self.prototype.clone())
.writable(false)
.enumerable(false)
.configurable(false),
);

let object = object.as_shared();

{
let mut prototype = self.prototype.borrow_mut();
prototype.set_prototype(self.inherits);
prototype.insert(
CONSTRUCTOR,
PropertyDescriptor::builder()
.value(object.clone())
.value(object)
.writable(self.attributes.writable())
.enumerable(self.attributes.enumerable())
.configurable(self.attributes.configurable()),
);
}
let mut object = object.borrow_mut();
object.insert(
PROTOTYPE,
PropertyDescriptor::builder()
.value(self.prototype)
.writable(false)
.enumerable(false)
.configurable(false),
);
}
}

impl ApplyToObject for ConstructorNoProto {
fn apply_to(self, _: &JsObject) {}
fn apply_to(self, _: &mut BuiltInObjectInitializer) {}
}

impl ApplyToObject for OrdinaryFunction {
fn apply_to(self, _: &JsObject) {}
fn apply_to(self, _: &mut BuiltInObjectInitializer) {}
}

impl<S: ApplyToObject + IsConstructor> ApplyToObject for Callable<S> {
fn apply_to(self, object: &JsObject) {
self.kind.apply_to(object);

let function = function::Function::Native {
fn apply_to(self, object: &mut BuiltInObjectInitializer) {
let function = ObjectData::function(function::Function::Native {
function: NativeFunction::from_fn_ptr(self.function),
constructor: S::IS_CONSTRUCTOR.then_some(function::ConstructorKind::Base),
};

let length = PropertyDescriptor::builder()
.value(self.length)
.writable(false)
.enumerable(false)
.configurable(true);
let name = PropertyDescriptor::builder()
.value(self.name)
.writable(false)
.enumerable(false)
.configurable(true);
});
object.set_data(function);
object.insert(
utf16!("length"),
PropertyDescriptor::builder()
.value(self.length)
.writable(false)
.enumerable(false)
.configurable(true),
);
object.insert(
utf16!("name"),
PropertyDescriptor::builder()
.value(self.name)
.writable(false)
.enumerable(false)
.configurable(true),
);

{
let mut constructor = object.borrow_mut();
constructor.data = ObjectData::function(function);
constructor.insert(utf16!("length"), length);
constructor.insert(utf16!("name"), name);
}
self.kind.apply_to(object);
}
}

impl ApplyToObject for OrdinaryObject {
fn apply_to(self, _: &JsObject) {}
fn apply_to(self, _: &mut BuiltInObjectInitializer) {}
}

/// Builder for creating built-in objects, like `Array`.
Expand All @@ -514,7 +592,7 @@ impl ApplyToObject for OrdinaryObject {
#[must_use = "You need to call the `build` method in order for this to correctly assign the inner data"]
struct BuiltInBuilder<'ctx, Kind> {
intrinsics: &'ctx Intrinsics,
object: JsObject,
object: BuiltInObjectInitializer,
kind: Kind,
prototype: JsObject,
}
Expand All @@ -523,7 +601,10 @@ impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> {
fn new(intrinsics: &'ctx Intrinsics) -> BuiltInBuilder<'ctx, OrdinaryObject> {
BuiltInBuilder {
intrinsics,
object: JsObject::with_null_proto(),
object: BuiltInObjectInitializer::Unique {
object: Object::default(),
data: ObjectData::ordinary(),
},
kind: OrdinaryObject,
prototype: intrinsics.constructors().object().prototype(),
}
Expand All @@ -534,7 +615,7 @@ impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> {
) -> BuiltInBuilder<'ctx, OrdinaryObject> {
BuiltInBuilder {
intrinsics,
object: I::get(intrinsics),
object: BuiltInObjectInitializer::Shared(I::get(intrinsics)),
kind: OrdinaryObject,
prototype: intrinsics.constructors().object().prototype(),
}
Expand All @@ -546,7 +627,7 @@ impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> {
) -> BuiltInBuilder<'ctx, OrdinaryObject> {
BuiltInBuilder {
intrinsics,
object,
object: BuiltInObjectInitializer::Shared(object),
kind: OrdinaryObject,
prototype: intrinsics.constructors().object().prototype(),
}
Expand Down Expand Up @@ -579,7 +660,7 @@ impl<'ctx> BuiltInBuilder<'ctx, Callable<Constructor>> {
let constructor = SC::STANDARD_CONSTRUCTOR(intrinsics.constructors());
BuiltInBuilder {
intrinsics,
object: constructor.constructor(),
object: BuiltInObjectInitializer::Shared(constructor.constructor()),
kind: Callable {
function: SC::constructor,
name: js_string!(SC::NAME),
Expand Down Expand Up @@ -611,7 +692,12 @@ impl<'ctx> BuiltInBuilder<'ctx, Callable<Constructor>> {

impl<T> BuiltInBuilder<'_, T> {
/// Adds a new static method to the builtin object.
fn static_method<B>(self, function: NativeFunctionPointer, binding: B, length: usize) -> Self
fn static_method<B>(
mut self,
function: NativeFunctionPointer,
binding: B,
length: usize,
) -> Self
where
B: Into<FunctionBinding>,
{
Expand All @@ -622,7 +708,7 @@ impl<T> BuiltInBuilder<'_, T> {
.length(length)
.build();

self.object.borrow_mut().insert(
self.object.insert(
binding.binding,
PropertyDescriptor::builder()
.value(function)
Expand All @@ -634,7 +720,7 @@ impl<T> BuiltInBuilder<'_, T> {
}

/// Adds a new static data property to the builtin object.
fn static_property<K, V>(self, key: K, value: V, attribute: Attribute) -> Self
fn static_property<K, V>(mut self, key: K, value: V, attribute: Attribute) -> Self
where
K: Into<PropertyKey>,
V: Into<JsValue>,
Expand All @@ -644,13 +730,13 @@ impl<T> BuiltInBuilder<'_, T> {
.writable(attribute.writable())
.enumerable(attribute.enumerable())
.configurable(attribute.configurable());
self.object.borrow_mut().insert(key, property);
self.object.insert(key, property);
self
}

/// Adds a new static accessor property to the builtin object.
fn static_accessor<K>(
self,
mut self,
key: K,
get: Option<JsFunction>,
set: Option<JsFunction>,
Expand All @@ -664,7 +750,7 @@ impl<T> BuiltInBuilder<'_, T> {
.maybe_set(set)
.enumerable(attribute.enumerable())
.configurable(attribute.configurable());
self.object.borrow_mut().insert(key, property);
self.object.insert(key, property);
self
}

Expand Down Expand Up @@ -773,28 +859,22 @@ impl<FnTyp> BuiltInBuilder<'_, Callable<FnTyp>> {

impl BuiltInBuilder<'_, OrdinaryObject> {
/// Build the builtin object.
fn build(self) -> JsObject {
self.kind.apply_to(&self.object);
fn build(mut self) -> JsObject {
self.kind.apply_to(&mut self.object);

{
let mut object = self.object.borrow_mut();
object.set_prototype(self.prototype);
}
self.object.set_prototype(self.prototype);

self.object
self.object.into_shared()
}
}

impl<FnTyp: ApplyToObject + IsConstructor> BuiltInBuilder<'_, Callable<FnTyp>> {
/// Build the builtin callable.
fn build(self) -> JsFunction {
self.kind.apply_to(&self.object);
fn build(mut self) -> JsFunction {
self.kind.apply_to(&mut self.object);

{
let mut object = self.object.borrow_mut();
object.set_prototype(self.prototype);
}
self.object.set_prototype(self.prototype);

JsFunction::from_object_unchecked(self.object)
JsFunction::from_object_unchecked(self.object.into_shared())
}
}
Loading

0 comments on commit ed2f008

Please sign in to comment.