Browse Source

Change type of object prototypes to `Option<JsObject>` (#1640)

pull/1646/head
jedel1043 3 years ago committed by GitHub
parent
commit
510623b0e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      boa/src/builtins/array_buffer/mod.rs
  2. 10
      boa/src/builtins/boolean/tests.rs
  3. 1
      boa/src/builtins/console/mod.rs
  4. 2
      boa/src/builtins/error/eval.rs
  5. 2
      boa/src/builtins/error/range.rs
  6. 2
      boa/src/builtins/error/reference.rs
  7. 2
      boa/src/builtins/error/syntax.rs
  8. 2
      boa/src/builtins/error/type.rs
  9. 2
      boa/src/builtins/error/uri.rs
  10. 23
      boa/src/builtins/json/tests.rs
  11. 5
      boa/src/builtins/object/for_in_iterator.rs
  12. 44
      boa/src/builtins/object/mod.rs
  13. 15
      boa/src/builtins/reflect/mod.rs
  14. 2
      boa/src/builtins/typed_array/integer_indexed_object.rs
  15. 4
      boa/src/builtins/typed_array/mod.rs
  16. 14
      boa/src/environment/function_environment_record.rs
  17. 9
      boa/src/exec/tests.rs
  18. 84
      boa/src/object/internal_methods/mod.rs
  19. 63
      boa/src/object/jsobject.rs
  20. 58
      boa/src/object/mod.rs
  21. 6
      boa/src/value/display.rs
  22. 6
      boa/src/value/mod.rs

2
boa/src/builtins/array_buffer/mod.rs

@ -307,7 +307,7 @@ impl ArrayBuffer {
context,
)?;
let obj = context.construct_object();
obj.set_prototype_instance(prototype.into());
obj.set_prototype(prototype.into());
// 2. Let block be ? CreateByteDataBlock(byteLength).
// TODO: for now just a arbitrary limit to not OOM.

10
boa/src/builtins/boolean/tests.rs

@ -1,4 +1,4 @@
use crate::{forward, forward_val, Context, JsValue};
use crate::{forward, forward_val, Context};
/// Test the correct type is returned from call and construct
#[allow(clippy::unwrap_used)]
@ -58,8 +58,8 @@ fn instances_have_correct_proto_set() {
let bool_instance = forward_val(&mut context, "boolInstance").expect("value expected");
let bool_prototype = forward_val(&mut context, "boolProto").expect("value expected");
assert!(JsValue::same_value(
&bool_instance.as_object().unwrap().prototype_instance(),
&bool_prototype
));
assert_eq!(
&*bool_instance.as_object().unwrap().prototype(),
&bool_prototype.as_object()
);
}

1
boa/src/builtins/console/mod.rs

@ -568,7 +568,6 @@ impl Console {
LogMessage::Info(display_obj(args.get_or_undefined(0), true)),
context.console(),
);
Ok(JsValue::undefined())
}
}

2
boa/src/builtins/error/eval.rs

@ -46,7 +46,7 @@ impl BuiltIn for EvalError {
)
.name(Self::NAME)
.length(Self::LENGTH)
.inherit(error_prototype.into())
.inherit(error_prototype)
.property("name", Self::NAME, attribute)
.property("message", "", attribute)
.build();

2
boa/src/builtins/error/range.rs

@ -43,7 +43,7 @@ impl BuiltIn for RangeError {
)
.name(Self::NAME)
.length(Self::LENGTH)
.inherit(error_prototype.into())
.inherit(error_prototype)
.property("name", Self::NAME, attribute)
.property("message", "", attribute)
.build();

2
boa/src/builtins/error/reference.rs

@ -42,7 +42,7 @@ impl BuiltIn for ReferenceError {
)
.name(Self::NAME)
.length(Self::LENGTH)
.inherit(error_prototype.into())
.inherit(error_prototype)
.property("name", Self::NAME, attribute)
.property("message", "", attribute)
.build();

2
boa/src/builtins/error/syntax.rs

@ -45,7 +45,7 @@ impl BuiltIn for SyntaxError {
)
.name(Self::NAME)
.length(Self::LENGTH)
.inherit(error_prototype.into())
.inherit(error_prototype)
.property("name", Self::NAME, attribute)
.property("message", "", attribute)
.build();

2
boa/src/builtins/error/type.rs

@ -48,7 +48,7 @@ impl BuiltIn for TypeError {
)
.name(Self::NAME)
.length(Self::LENGTH)
.inherit(error_prototype.into())
.inherit(error_prototype)
.property("name", Self::NAME, attribute)
.property("message", "", attribute)
.build();

2
boa/src/builtins/error/uri.rs

@ -44,7 +44,7 @@ impl BuiltIn for UriError {
)
.name(Self::NAME)
.length(Self::LENGTH)
.inherit(error_prototype.into())
.inherit(error_prototype)
.property("name", Self::NAME, attribute)
.property("message", "", attribute)
.build();

23
boa/src/builtins/json/tests.rs

@ -1,4 +1,4 @@
use crate::{forward, forward_val, Context, JsValue};
use crate::{forward, forward_val, Context};
#[test]
fn json_sanity() {
@ -413,27 +413,22 @@ fn json_parse_sets_prototypes() {
.unwrap()
.as_object()
.unwrap()
.prototype_instance();
.prototype()
.clone();
let array_prototype = forward_val(&mut context, r#"jsonObj.arr"#)
.unwrap()
.as_object()
.unwrap()
.prototype_instance();
let global_object_prototype: JsValue = context
.prototype()
.clone();
let global_object_prototype = context
.standard_objects()
.object_object()
.prototype()
.into();
let global_array_prototype: JsValue =
context.standard_objects().array_object().prototype().into();
assert!(JsValue::same_value(
&object_prototype,
&global_object_prototype
));
assert!(JsValue::same_value(
&array_prototype,
&global_array_prototype
));
let global_array_prototype = context.standard_objects().array_object().prototype().into();
assert_eq!(object_prototype, global_object_prototype);
assert_eq!(array_prototype, global_array_prototype);
}
#[test]

5
boa/src/builtins/object/for_in_iterator.rs

@ -98,8 +98,9 @@ impl ForInIterator {
}
}
}
match object.prototype_instance().to_object(context) {
Ok(o) => {
let proto = object.prototype().clone();
match proto {
Some(o) => {
object = o;
}
_ => {

44
boa/src/builtins/object/mod.rs

@ -22,7 +22,7 @@ use crate::{
},
property::{Attribute, DescriptorKind, PropertyDescriptor, PropertyKey, PropertyNameKind},
symbol::WellKnownSymbols,
value::{JsValue, Type},
value::JsValue,
BoaProfiler, Context, JsResult,
};
@ -53,7 +53,7 @@ impl BuiltIn for Object {
)
.name(Self::NAME)
.length(Self::LENGTH)
.inherit(JsValue::null())
.inherit(None)
.method(Self::has_own_property, "hasOwnProperty", 0)
.method(Self::property_is_enumerable, "propertyIsEnumerable", 0)
.method(Self::to_string, "toString", 0)
@ -284,7 +284,9 @@ impl Object {
let obj = args[0].clone().to_object(ctx)?;
// 2. Return ? obj.[[GetPrototypeOf]]().
Ok(obj.prototype_instance())
Ok(obj
.__get_prototype_of__(ctx)?
.map_or(JsValue::Null, JsValue::new))
}
/// Set the `prototype` of an object.
@ -301,32 +303,32 @@ impl Object {
}
// 1. Set O to ? RequireObjectCoercible(O).
let obj = args
let o = args
.get(0)
.cloned()
.unwrap_or_default()
.require_object_coercible(ctx)?
.clone();
// 2. If Type(proto) is neither Object nor Null, throw a TypeError exception.
let proto = args.get_or_undefined(1);
if !matches!(proto.get_type(), Type::Object | Type::Null) {
return ctx.throw_type_error(format!(
"expected an object or null, got {}",
proto.type_of()
));
}
let proto = match args.get_or_undefined(1) {
JsValue::Object(obj) => Some(obj.clone()),
JsValue::Null => None,
// 2. If Type(proto) is neither Object nor Null, throw a TypeError exception.
val => {
return ctx
.throw_type_error(format!("expected an object or null, got {}", val.type_of()))
}
};
// 3. If Type(O) is not Object, return O.
if !obj.is_object() {
return Ok(obj);
}
let mut obj = if let Some(obj) = o.as_object() {
obj
} else {
// 3. If Type(O) is not Object, return O.
return Ok(o);
};
// 4. Let status be ? O.[[SetPrototypeOf]](proto).
let status = obj
.as_object()
.expect("obj was not an object")
.__set_prototype_of__(proto.clone(), ctx)?;
let status = obj.__set_prototype_of__(proto, ctx)?;
// 5. If status is false, throw a TypeError exception.
if !status {
@ -334,7 +336,7 @@ impl Object {
}
// 6. Return O.
Ok(obj)
Ok(o)
}
/// `Object.prototype.isPrototypeOf( proto )`

15
boa/src/builtins/reflect/mod.rs

@ -244,7 +244,9 @@ impl Reflect {
.get(0)
.and_then(|v| v.as_object())
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
target.__get_prototype_of__(context)
Ok(target
.__get_prototype_of__(context)?
.map_or(JsValue::Null, JsValue::new))
}
/// Returns `true` if the object has the property, `false` otherwise.
@ -377,10 +379,11 @@ impl Reflect {
.get(0)
.and_then(|v| v.as_object())
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
let proto = args.get_or_undefined(1);
if !proto.is_null() && !proto.is_object() {
return context.throw_type_error("proto must be an object or null");
}
Ok(target.__set_prototype_of__(proto.clone(), context)?.into())
let proto = match args.get_or_undefined(1) {
JsValue::Object(obj) => Some(obj.clone()),
JsValue::Null => None,
_ => return context.throw_type_error("proto must be an object or null"),
};
Ok(target.__set_prototype_of__(proto, context)?.into())
}
}

2
boa/src/builtins/typed_array/integer_indexed_object.rs

@ -77,7 +77,7 @@ impl IntegerIndexed {
a.borrow_mut().data = ObjectData::integer_indexed(data);
// 10. Set A.[[Prototype]] to prototype.
a.set_prototype_instance(prototype.into());
a.set_prototype(prototype.into());
// 11. Return A.
a

4
boa/src/builtins/typed_array/mod.rs

@ -82,8 +82,8 @@ macro_rules! typed_array {
TypedArrayName::$ty.element_size(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
)
.custom_prototype(typed_array_constructor.into())
.inherit(typed_array_constructor_proto.into())
.custom_prototype(typed_array_constructor)
.inherit(typed_array_constructor_proto)
.build()
.into()
}

14
boa/src/environment/function_environment_record.rs

@ -17,7 +17,7 @@ use crate::{
lexical_environment::{Environment, EnvironmentType, VariableScope},
},
gc::{empty_trace, Finalize, Trace},
object::JsObject,
object::{JsObject, JsPrototype},
Context, JsResult, JsValue,
};
@ -114,21 +114,23 @@ impl FunctionEnvironmentRecord {
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-getsuperbase
pub fn get_super_base(&self) -> JsValue {
pub fn get_super_base(&self, context: &mut Context) -> JsResult<Option<JsPrototype>> {
// 1. Let home be envRec.[[FunctionObject]].[[HomeObject]].
let home = &self.home_object;
// 2. If home has the value undefined, return undefined.
if home.is_undefined() {
JsValue::undefined()
Ok(None)
} else {
// 3. Assert: Type(home) is Object.
assert!(home.is_object());
// 4. Return ? home.[[GetPrototypeOf]]().
home.as_object()
.expect("home_object must be an Object")
.prototype_instance()
Ok(Some(
home.as_object()
.expect("home_object must be an Object")
.__get_prototype_of__(context)?,
))
}
}
}

9
boa/src/exec/tests.rs

@ -791,9 +791,12 @@ mod in_operator {
let bar_val = forward_val(&mut context, "bar").unwrap();
let bar_obj = bar_val.as_object().unwrap();
let foo_val = forward_val(&mut context, "Foo").unwrap();
assert!(bar_obj
.prototype_instance()
.strict_equals(&foo_val.get_field("prototype", &mut context).unwrap()));
assert_eq!(
&*bar_obj.prototype(),
&foo_val
.as_object()
.and_then(|obj| obj.get("prototype", &mut context).unwrap().as_object())
);
}
}

84
boa/src/object/internal_methods/mod.rs

@ -13,7 +13,7 @@ use crate::{
BoaProfiler, Context, JsResult,
};
use super::PROTOTYPE;
use super::{JsPrototype, PROTOTYPE};
pub(super) mod arguments;
pub(super) mod array;
@ -31,7 +31,7 @@ impl JsObject {
/// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getprototypeof
#[inline]
#[track_caller]
pub(crate) fn __get_prototype_of__(&self, context: &mut Context) -> JsResult<JsValue> {
pub(crate) fn __get_prototype_of__(&self, context: &mut Context) -> JsResult<JsPrototype> {
let func = self.borrow().data.internal_methods.__get_prototype_of__;
func(self, context)
}
@ -47,7 +47,7 @@ impl JsObject {
#[inline]
pub(crate) fn __set_prototype_of__(
&mut self,
val: JsValue,
val: JsPrototype,
context: &mut Context,
) -> JsResult<bool> {
let func = self.borrow().data.internal_methods.__set_prototype_of__;
@ -245,8 +245,8 @@ pub(crate) static ORDINARY_INTERNAL_METHODS: InternalObjectMethods = InternalObj
/// For a guide on how to implement exotic internal methods, see `ORDINARY_INTERNAL_METHODS`.
#[derive(Clone, Copy)]
pub(crate) struct InternalObjectMethods {
pub(crate) __get_prototype_of__: fn(&JsObject, &mut Context) -> JsResult<JsValue>,
pub(crate) __set_prototype_of__: fn(&JsObject, JsValue, &mut Context) -> JsResult<bool>,
pub(crate) __get_prototype_of__: fn(&JsObject, &mut Context) -> JsResult<JsPrototype>,
pub(crate) __set_prototype_of__: fn(&JsObject, JsPrototype, &mut Context) -> JsResult<bool>,
pub(crate) __is_extensible__: fn(&JsObject, &mut Context) -> JsResult<bool>,
pub(crate) __prevent_extensions__: fn(&JsObject, &mut Context) -> JsResult<bool>,
pub(crate) __get_own_property__:
@ -271,9 +271,9 @@ pub(crate) struct InternalObjectMethods {
pub(crate) fn ordinary_get_prototype_of(
obj: &JsObject,
_context: &mut Context,
) -> JsResult<JsValue> {
) -> JsResult<JsPrototype> {
// 1. Return O.[[Prototype]].
Ok(obj.borrow().prototype.clone())
Ok(obj.prototype().as_ref().cloned())
}
/// Abstract operation `OrdinarySetPrototypeOf`.
@ -285,23 +285,23 @@ pub(crate) fn ordinary_get_prototype_of(
#[inline]
pub(crate) fn ordinary_set_prototype_of(
obj: &JsObject,
val: JsValue,
context: &mut Context,
val: JsPrototype,
_: &mut Context,
) -> JsResult<bool> {
// 1. Assert: Either Type(V) is Object or Type(V) is Null.
debug_assert!(val.is_object() || val.is_null());
{
// 2. Let current be O.[[Prototype]].
let current = obj.prototype();
// 2. Let current be O.[[Prototype]].
let current = obj.__get_prototype_of__(context)?;
// 3. If SameValue(V, current) is true, return true.
if JsValue::same_value(&current, &val) {
return Ok(true);
// 3. If SameValue(V, current) is true, return true.
if val == *current {
return Ok(true);
}
}
// 4. Let extensible be O.[[Extensible]].
// 5. If extensible is false, return false.
if !obj.__is_extensible__(context)? {
if !obj.extensible() {
return Ok(false);
}
@ -309,37 +309,29 @@ pub(crate) fn ordinary_set_prototype_of(
let mut p = val.clone();
// 7. Let done be false.
let mut done = false;
// 8. Repeat, while done is false,
while !done {
match p {
// a. If p is null, set done to true.
JsValue::Null => done = true,
JsValue::Object(ref proto) => {
// b. Else if SameValue(p, O) is true, return false.
if JsObject::equals(proto, obj) {
return Ok(false);
}
// c. Else,
// i. If p.[[GetPrototypeOf]] is not the ordinary object internal method defined
// in 10.1.1, set done to true.
else if proto.borrow().data.internal_methods.__get_prototype_of__ as usize
!= ordinary_get_prototype_of as usize
{
done = true;
}
// ii. Else, set p to p.[[Prototype]].
else {
p = proto.__get_prototype_of__(context)?;
}
}
_ => unreachable!(),
// a. If p is null, set done to true.
while let Some(proto) = p {
// b. Else if SameValue(p, O) is true, return false.
if &proto == obj {
return Ok(false);
}
// c. Else,
// i. If p.[[GetPrototypeOf]] is not the ordinary object internal method defined
// in 10.1.1, set done to true.
else if proto.borrow().data.internal_methods.__get_prototype_of__ as usize
!= ordinary_get_prototype_of as usize
{
break;
}
// ii. Else, set p to p.[[Prototype]].
else {
p = proto.prototype().clone();
}
}
// 9. Set O.[[Prototype]] to V.
obj.borrow_mut().prototype = val;
obj.set_prototype(val);
// 10. Return true.
Ok(true)
@ -454,7 +446,7 @@ pub(crate) fn ordinary_has_property(
let parent = obj.__get_prototype_of__(context)?;
// 5. If parent is not null, then
if let JsValue::Object(ref object) = parent {
if let Some(object) = parent {
// a. Return ? parent.[[HasProperty]](P).
object.__has_property__(key, context)
} else {
@ -483,7 +475,7 @@ pub(crate) fn ordinary_get(
// If desc is undefined, then
None => {
// a. Let parent be ? O.[[GetPrototypeOf]]().
if let Some(parent) = obj.__get_prototype_of__(context)?.as_object() {
if let Some(parent) = obj.__get_prototype_of__(context)? {
// c. Return ? parent.[[Get]](P, Receiver).
parent.__get__(key, receiver, context)
}
@ -537,7 +529,7 @@ pub(crate) fn ordinary_set(
// 2. If ownDesc is undefined, then
// a. Let parent be ? O.[[GetPrototypeOf]]().
// b. If parent is not null, then
else if let Some(ref mut parent) = obj.__get_prototype_of__(context)?.as_object() {
else if let Some(parent) = obj.__get_prototype_of__(context)? {
// i. Return ? parent.[[Set]](P, V, Receiver).
return parent.__set__(key, value, receiver, context);
}

63
boa/src/object/jsobject.rs

@ -2,7 +2,7 @@
//!
//! The `JsObject` is a garbage collected Object.
use super::{NativeObject, Object};
use super::{JsPrototype, NativeObject, Object};
use crate::{
object::{ObjectData, ObjectKind},
property::{PropertyDescriptor, PropertyKey},
@ -40,21 +40,6 @@ pub type RefMut<'a, T, U> = GcCellRefMut<'a, T, U>;
#[derive(Trace, Finalize, Clone, Default)]
pub struct JsObject(Gc<GcCell<Object>>);
/// The body of a JavaScript function.
///
/// This is needed for the call method since we cannot mutate the function itself since we
/// already borrow it so we get the function body clone it then drop the borrow and run the body
#[cfg(not(feature = "vm"))]
enum FunctionBody {
BuiltInFunction(NativeFunctionSignature),
BuiltInConstructor(NativeFunctionSignature),
Closure {
function: Box<dyn ClosureFunctionSignature>,
captures: Captures,
},
Ordinary(RcStatementList),
}
impl JsObject {
/// Create a new `JsObject` from an internal `Object`.
#[inline]
@ -76,7 +61,7 @@ impl JsObject {
pub fn from_proto_and_data<O: Into<Option<JsObject>>>(prototype: O, data: ObjectData) -> Self {
Self::from_object(Object {
data,
prototype: prototype.into().map_or(JsValue::Null, JsValue::new),
prototype: prototype.into(),
extensible: true,
properties: Default::default(),
})
@ -160,6 +145,21 @@ impl JsObject {
use super::internal_methods::get_prototype_from_constructor;
/// The body of a JavaScript function.
///
/// This is needed for the call method since we cannot mutate the function itself since we
/// already borrow it so we get the function body clone it then drop the borrow and run the body
#[cfg(not(feature = "vm"))]
enum FunctionBody {
BuiltInFunction(NativeFunctionSignature),
BuiltInConstructor(NativeFunctionSignature),
Closure {
function: Box<dyn ClosureFunctionSignature>,
captures: Captures,
},
Ordinary(RcStatementList),
}
let this_function_object = self.clone();
let mut has_parameter_expressions = false;
@ -515,8 +515,18 @@ impl JsObject {
/// Panics if the object is currently mutably borrowed.
#[inline]
#[track_caller]
pub fn prototype_instance(&self) -> JsValue {
self.borrow().prototype_instance().clone()
pub fn prototype(&self) -> Ref<'_, JsPrototype> {
Ref::map(self.borrow(), |obj| obj.prototype())
}
/// Get the extensibility of the object.
///
/// # Panics
///
/// Panics if the object is currently mutably borrowed.
#[inline]
pub(crate) fn extensible(&self) -> bool {
self.borrow().extensible
}
/// Set the prototype of the object.
@ -524,11 +534,10 @@ impl JsObject {
/// # Panics
///
/// Panics if the object is currently mutably borrowed
/// or if th prototype is not an object or undefined.
#[inline]
#[track_caller]
pub fn set_prototype_instance(&self, prototype: JsValue) -> bool {
self.borrow_mut().set_prototype_instance(prototype)
pub fn set_prototype(&self, prototype: JsPrototype) -> bool {
self.borrow_mut().set_prototype(prototype)
}
/// Checks if it's an `Array` object.
@ -726,9 +735,9 @@ impl JsObject {
// a. Set O to ? O.[[GetPrototypeOf]]().
// b. If O is null, return false.
let mut object = object.__get_prototype_of__(context)?;
while let Some(object_prototype) = object.as_object() {
while let Some(object_prototype) = object {
// c. If SameValue(P, O) is true, return true.
if JsObject::equals(&prototype, &object_prototype) {
if prototype == object_prototype {
return Ok(true);
}
// a. Set O to ? O.[[GetPrototypeOf]]().
@ -972,6 +981,12 @@ impl AsRef<GcCell<Object>> for JsObject {
}
}
impl PartialEq for JsObject {
fn eq(&self, other: &Self) -> bool {
JsObject::equals(self, other)
}
}
/// An error returned by [`JsObject::try_borrow`](struct.JsObject.html#method.try_borrow).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BorrowError;

58
boa/src/object/mod.rs

@ -49,6 +49,8 @@ use self::internal_methods::{
/// Static `prototype`, usually set on constructors as a key to point to their respective prototype object.
pub static PROTOTYPE: &str = "prototype";
pub type JsPrototype = Option<JsObject>;
/// This trait allows Rust types to be passed around as objects.
///
/// This is automatically implemented, when a type implements `Debug`, `Any` and `Trace`.
@ -72,14 +74,15 @@ impl<T: Any + Debug + Trace> NativeObject for T {
}
}
/// The internal representation of an JavaScript object.
/// The internal representation of a JavaScript object.
#[derive(Debug, Trace, Finalize)]
pub struct Object {
/// The type of the object.
pub data: ObjectData,
/// The collection of properties contained in the object
properties: PropertyMap,
/// Instance prototype `__proto__`.
prototype: JsValue,
prototype: JsPrototype,
/// Whether it can have new properties added to it.
extensible: bool,
}
@ -365,7 +368,7 @@ impl Default for Object {
Self {
data: ObjectData::ordinary(),
properties: PropertyMap::default(),
prototype: JsValue::null(),
prototype: None,
extensible: true,
}
}
@ -936,7 +939,7 @@ impl Object {
/// Gets the prototype instance of this object.
#[inline]
pub fn prototype_instance(&self) -> &JsValue {
pub fn prototype(&self) -> &JsPrototype {
&self.prototype
}
@ -947,15 +950,15 @@ impl Object {
/// [spec]: https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods
#[inline]
#[track_caller]
pub fn set_prototype_instance(&mut self, prototype: JsValue) -> bool {
assert!(prototype.is_null() || prototype.is_object());
pub fn set_prototype<O: Into<JsPrototype>>(&mut self, prototype: O) -> bool {
let prototype = prototype.into();
if self.extensible {
self.prototype = prototype;
true
} else {
// If target is non-extensible, [[SetPrototypeOf]] must return false
// unless V is the SameValue as the target's observed [[GetPrototypeOf]] value.
JsValue::same_value(&prototype, &self.prototype)
self.prototype == prototype
}
}
@ -1264,13 +1267,7 @@ impl<'context> FunctionBuilder<'context> {
pub(crate) fn build_function_prototype(&mut self, object: &JsObject) {
let mut object = object.borrow_mut();
object.data = ObjectData::function(self.function.take().unwrap());
object.set_prototype_instance(
self.context
.standard_objects()
.object_object()
.prototype()
.into(),
);
object.set_prototype(self.context.standard_objects().object_object().prototype());
let property = PropertyDescriptor::builder()
.writable(false)
@ -1387,8 +1384,8 @@ pub struct ConstructorBuilder<'context> {
length: usize,
callable: bool,
constructable: bool,
inherit: Option<JsValue>,
custom_prototype: Option<JsValue>,
inherit: Option<JsPrototype>,
custom_prototype: Option<JsPrototype>,
}
impl Debug for ConstructorBuilder<'_> {
@ -1642,9 +1639,8 @@ impl<'context> ConstructorBuilder<'context> {
///
/// Default is `Object.prototype`
#[inline]
pub fn inherit(&mut self, prototype: JsValue) -> &mut Self {
assert!(prototype.is_object() || prototype.is_null());
self.inherit = Some(prototype);
pub fn inherit<O: Into<JsPrototype>>(&mut self, prototype: O) -> &mut Self {
self.inherit = Some(prototype.into());
self
}
@ -1652,8 +1648,8 @@ impl<'context> ConstructorBuilder<'context> {
///
/// Default is `Function.prototype`
#[inline]
pub fn custom_prototype(&mut self, prototype: JsValue) -> &mut Self {
self.custom_prototype = Some(prototype);
pub fn custom_prototype<O: Into<JsPrototype>>(&mut self, prototype: O) -> &mut Self {
self.custom_prototype = Some(prototype.into());
self
}
@ -1688,15 +1684,14 @@ impl<'context> ConstructorBuilder<'context> {
constructor.insert("length", length);
constructor.insert("name", name);
if let Some(proto) = &self.custom_prototype {
constructor.set_prototype_instance(proto.clone());
if let Some(proto) = self.custom_prototype.take() {
constructor.set_prototype(proto);
} else {
constructor.set_prototype_instance(
constructor.set_prototype(
self.context
.standard_objects()
.function_object()
.prototype()
.into(),
.prototype(),
);
}
constructor.insert_property(
@ -1721,15 +1716,10 @@ impl<'context> ConstructorBuilder<'context> {
);
if let Some(proto) = self.inherit.take() {
prototype.set_prototype_instance(proto);
prototype.set_prototype(proto);
} else {
prototype.set_prototype_instance(
self.context
.standard_objects()
.object_object()
.prototype()
.into(),
);
prototype
.set_prototype(self.context.standard_objects().object_object().prototype());
}
}

6
boa/src/value/display.rs

@ -31,18 +31,18 @@ macro_rules! print_obj_value {
(internals of $obj:expr, $display_fn:ident, $indent:expr, $encounters:expr) => {
{
let object = $obj.borrow();
if object.prototype_instance().is_object() {
if let Some(object) = object.prototype() {
vec![format!(
"{:>width$}: {}",
"__proto__",
$display_fn(object.prototype_instance(), $encounters, $indent.wrapping_add(4), true),
$display_fn(&object.clone().into(), $encounters, $indent.wrapping_add(4), true),
width = $indent,
)]
} else {
vec![format!(
"{:>width$}: {}",
"__proto__",
object.prototype_instance().display(),
JsValue::Null.display(),
width = $indent,
)]
}

6
boa/src/value/mod.rs

@ -290,7 +290,11 @@ impl JsValue {
return property;
}
object.borrow().prototype_instance().get_property(key)
object
.prototype()
.as_ref()
.map_or(JsValue::Null, |obj| obj.clone().into())
.get_property(key)
}
_ => None,
}

Loading…
Cancel
Save