Browse Source

Fixed some panics (#1029)

* Fixed some panics, Object.setPrototypeOf and Object.getPrototypeOf are almost spec compliant

* Small documentation fix

* Fixed clippy lint

* Added `RequireObjectCoercible`

* Fixed compilation error

* cargo fmt
pull/1036/head
Iban Eguia 4 years ago committed by GitHub
parent
commit
5e78ff83f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 69
      boa/src/builtins/object/mod.rs
  2. 2
      boa/src/object/gcobject.rs
  3. 20
      boa/src/object/mod.rs
  4. 3
      boa/src/value/display.rs

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

@ -19,7 +19,7 @@ use crate::{
property::Attribute,
property::DataDescriptor,
property::PropertyDescriptor,
value::{same_value, Value},
value::{same_value, Type, Value},
BoaProfiler, Context, Result,
};
@ -243,18 +243,67 @@ impl Object {
}
/// Get the `prototype` of an object.
pub fn get_prototype_of(_: &Value, args: &[Value], _: &mut Context) -> Result<Value> {
let obj = args.get(0).expect("Cannot get object");
Ok(obj
.as_object()
.map_or_else(Value::undefined, |object| object.prototype_instance()))
pub fn get_prototype_of(_: &Value, args: &[Value], ctx: &mut Context) -> Result<Value> {
if args.is_empty() {
return ctx.throw_type_error(
"Object.getPrototypeOf: At least 1 argument required, but only 0 passed",
);
}
// 1. Let obj be ? ToObject(O).
let obj = args[0].clone().to_object(ctx)?;
// 2. Return ? obj.[[GetPrototypeOf]]().
Ok(obj.prototype_instance())
}
/// Set the `prototype` of an object.
pub fn set_prototype_of(_: &Value, args: &[Value], _: &mut Context) -> Result<Value> {
let obj = args.get(0).expect("Cannot get object").clone();
let proto = args.get(1).expect("Cannot get object").clone();
obj.as_object().unwrap().set_prototype_instance(proto);
///
/// [More information][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-object.setprototypeof
pub fn set_prototype_of(_: &Value, args: &[Value], ctx: &mut Context) -> Result<Value> {
if args.len() < 2 {
return ctx.throw_type_error(format!(
"Object.setPrototypeOf: At least 2 arguments required, but only {} passed",
args.len()
));
}
// 1. Set O to ? RequireObjectCoercible(O).
let obj = 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(1).cloned().unwrap_or_default();
if !matches!(proto.get_type(), Type::Object | Type::Null) {
return ctx.throw_type_error(format!(
"expected an object or null, got {}",
proto.get_type().as_str()
));
}
// 3. If Type(O) is not Object, return O.
if obj.get_type() != Type::Object {
return Ok(obj);
}
// 4. Let status be ? O.[[SetPrototypeOf]](proto).
let status = obj
.as_object()
.expect("obj was not an object")
.set_prototype_instance(proto);
// 5. If status is false, throw a TypeError exception.
if !status {
return ctx.throw_type_error("can't set prototype of this object");
}
// 6. Return O.
Ok(obj)
}

2
boa/src/object/gcobject.rs

@ -550,7 +550,7 @@ impl GcObject {
/// or if th prototype is not an object or undefined.
#[inline]
#[track_caller]
pub fn set_prototype_instance(&mut self, prototype: Value) {
pub fn set_prototype_instance(&mut self, prototype: Value) -> bool {
self.borrow_mut().set_prototype_instance(prototype)
}

20
boa/src/object/mod.rs

@ -12,7 +12,7 @@ use crate::{
context::StandardConstructor,
gc::{Finalize, Trace},
property::{Attribute, DataDescriptor, PropertyDescriptor, PropertyKey},
value::{RcBigInt, RcString, RcSymbol, Value},
value::{same_value, RcBigInt, RcString, RcSymbol, Value},
BoaProfiler, Context,
};
use rustc_hash::FxHashMap;
@ -483,11 +483,23 @@ impl Object {
&self.prototype
}
#[track_caller]
/// Sets the prototype instance of the object.
///
/// [More information][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods
#[inline]
pub fn set_prototype_instance(&mut self, prototype: Value) {
#[track_caller]
pub fn set_prototype_instance(&mut self, prototype: Value) -> bool {
assert!(prototype.is_null() || prototype.is_object());
self.prototype = prototype
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.
same_value(&prototype, &self.prototype)
}
}
/// Similar to `Value::new_object`, but you can pass a prototype to create from, plus a kind

3
boa/src/value/display.rs

@ -110,7 +110,8 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool, print_children:
.unwrap()
.value()
.as_number()
.unwrap() as i32;
.map(|n| n as i32)
.unwrap_or_default();
if print_children {
if len == 0 {

Loading…
Cancel
Save