Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed some panics #1029

Merged
merged 6 commits into from
Jan 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 59 additions & 10 deletions boa/src/builtins/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
property::Attribute,
property::DataDescriptor,
property::PropertyDescriptor,
value::{same_value, Value},
value::{same_value, Type, Value},
BoaProfiler, Context, Result,
};

Expand Down Expand Up @@ -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)
}

Expand Down
2 changes: 1 addition & 1 deletion boa/src/object/gcobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
20 changes: 16 additions & 4 deletions boa/src/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion boa/src/value/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down