Skip to content

Commit

Permalink
Initial implementation of NaN-boxing
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Feb 21, 2022
1 parent 46f96d4 commit 7f71cef
Show file tree
Hide file tree
Showing 47 changed files with 1,371 additions and 794 deletions.
3 changes: 2 additions & 1 deletion boa/src/builtins/array/array_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ impl ArrayIterator {
///
/// [spec]: https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
pub(crate) fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut array_iterator = this.as_object().map(JsObject::borrow_mut);
let array_iterator = this.as_object();
let mut array_iterator = array_iterator.as_ref().map(JsObject::borrow_mut);
let array_iterator = array_iterator
.as_mut()
.and_then(|obj| obj.as_array_iterator_mut())
Expand Down
20 changes: 9 additions & 11 deletions boa/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
},
property::{Attribute, PropertyDescriptor, PropertyNameKind},
symbol::WellKnownSymbols,
value::{IntegerOrInfinity, JsValue},
value::{IntegerOrInfinity, JsValue, JsVariant},
BoaProfiler, Context, JsResult, JsString,
};
use std::cmp::{max, min, Ordering};
Expand Down Expand Up @@ -365,8 +365,7 @@ impl Array {
Ok(
c.construct(&[JsValue::new(length)], &c.clone().into(), context)?
.as_object()
.expect("constructing an object should always return an object")
.clone(),
.expect("constructing an object should always return an object"),
)
} else {
context.throw_type_error("Symbol.species must be a constructor")
Expand Down Expand Up @@ -449,7 +448,6 @@ impl Array {
Some(constructor) => constructor
.construct(&[len.into()], this, context)?
.as_object()
.cloned()
.ok_or_else(|| {
context.construct_type_error("object constructor didn't return an object")
})?,
Expand Down Expand Up @@ -1570,7 +1568,7 @@ impl Array {
source_len as u64,
0,
1,
Some(mapper_function),
Some(&mapper_function),
args.get_or_undefined(1),
context,
)?;
Expand Down Expand Up @@ -1660,7 +1658,7 @@ impl Array {
// 4. Set targetIndex to ? FlattenIntoArray(target, element, elementLen, targetIndex, newDepth)
target_index = Self::flatten_into_array(
target,
element,
&element,
element_len as u64,
target_index,
new_depth,
Expand Down Expand Up @@ -2197,9 +2195,9 @@ impl Array {
context: &mut Context,
) -> JsResult<JsValue> {
// 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
let comparefn = match args.get_or_undefined(0) {
JsValue::Object(ref obj) if obj.is_callable() => Some(obj),
JsValue::Undefined => None,
let comparefn = match args.get_or_undefined(0).variant() {
JsVariant::Object(obj) if obj.is_callable() => Some(obj),
JsVariant::Undefined => None,
_ => {
return context.throw_type_error(
"The comparison function must be either a function or undefined",
Expand All @@ -2226,11 +2224,11 @@ impl Array {
}

// 4. If comparefn is not undefined, then
if let Some(cmp) = comparefn {
if let Some(ref cmp) = comparefn {
let args = [x.clone(), y.clone()];
// a. Let v be ? ToNumber(? Call(comparefn, undefined, « x, y »)).
let v = cmp
.call(&JsValue::Undefined, &args, context)?
.call(&JsValue::undefined(), &args, context)?
.to_number(context)?;
// b. If v is NaN, return +0𝔽.
// c. Return v.
Expand Down
4 changes: 2 additions & 2 deletions boa/src/builtins/array_buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl ArrayBuffer {
let new = ctor.construct(&[new_len.into()], &ctor.clone().into(), context)?;

// 17. Perform ? RequireInternalSlot(new, [[ArrayBufferData]]).
let new_obj = new.as_object().cloned().ok_or_else(|| {
let new_obj = new.as_object().ok_or_else(|| {
context.construct_type_error("ArrayBuffer constructor returned non-object value")
})?;

Expand Down Expand Up @@ -325,7 +325,7 @@ impl ArrayBuffer {
obj.borrow_mut().data = ObjectData::array_buffer(Self {
array_buffer_data: Some(block),
array_buffer_byte_length: byte_length,
array_buffer_detach_key: JsValue::Undefined,
array_buffer_detach_key: JsValue::undefined(),
});

// 5. Return obj.
Expand Down
1 change: 0 additions & 1 deletion boa/src/builtins/bigint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ impl BigInt {
value
// 1. If Type(value) is BigInt, return value.
.as_bigint()
.cloned()
// 2. If Type(value) is Object and value has a [[BigIntData]] internal slot, then
// a. Assert: Type(value.[[BigIntData]]) is BigInt.
// b. Return value.[[BigIntData]].
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/boolean/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ fn instances_have_correct_proto_set() {

assert_eq!(
&*bool_instance.as_object().unwrap().prototype(),
&bool_prototype.as_object().cloned()
&bool_prototype.as_object()
);
}
17 changes: 11 additions & 6 deletions boa/src/builtins/dataview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ impl DataView {
prototype,
ObjectData::data_view(Self {
// 11. Set O.[[ViewedArrayBuffer]] to buffer.
viewed_array_buffer: buffer_obj.clone(),
viewed_array_buffer: buffer_obj,
// 12. Set O.[[ByteLength]] to viewByteLength.
byte_length: view_byte_length,
// 13. Set O.[[ByteOffset]] to offset.
Expand Down Expand Up @@ -197,7 +197,8 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Let O be the this value.
// 2. Perform ? RequireInternalSlot(O, [[DataView]]).
let dataview = this.as_object().map(JsObject::borrow);
let dataview = this.as_object();
let dataview = dataview.as_ref().map(JsObject::borrow);
let dataview = dataview
.as_ref()
.and_then(|obj| obj.as_data_view())
Expand Down Expand Up @@ -226,7 +227,8 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Let O be the this value.
// 2. Perform ? RequireInternalSlot(O, [[DataView]]).
let dataview = this.as_object().map(JsObject::borrow);
let dataview = this.as_object();
let dataview = dataview.as_ref().map(JsObject::borrow);
let dataview = dataview
.as_ref()
.and_then(|obj| obj.as_data_view())
Expand Down Expand Up @@ -265,7 +267,8 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Let O be the this value.
// 2. Perform ? RequireInternalSlot(O, [[DataView]]).
let dataview = this.as_object().map(JsObject::borrow);
let dataview = this.as_object();
let dataview = dataview.as_ref().map(JsObject::borrow);
let dataview = dataview
.as_ref()
.and_then(|obj| obj.as_data_view())
Expand Down Expand Up @@ -305,7 +308,8 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Perform ? RequireInternalSlot(view, [[DataView]]).
// 2. Assert: view has a [[ViewedArrayBuffer]] internal slot.
let view = view.as_object().map(JsObject::borrow);
let view = view.as_object();
let view = view.as_ref().map(JsObject::borrow);
let view = view
.as_ref()
.and_then(|obj| obj.as_data_view())
Expand Down Expand Up @@ -664,7 +668,8 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Perform ? RequireInternalSlot(view, [[DataView]]).
// 2. Assert: view has a [[ViewedArrayBuffer]] internal slot.
let view = view.as_object().map(JsObject::borrow);
let view = view.as_object();
let view = view.as_ref().map(JsObject::borrow);
let view = view
.as_ref()
.and_then(|obj| obj.as_data_view())
Expand Down
35 changes: 18 additions & 17 deletions boa/src/builtins/date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
},
property::Attribute,
symbol::WellKnownSymbols,
value::{JsValue, PreferredType},
value::{JsValue, JsVariant, PreferredType},
BoaProfiler, Context, JsResult, JsString,
};
use chrono::{prelude::*, Duration, LocalResult};
Expand Down Expand Up @@ -400,24 +400,25 @@ impl Date {
context: &mut Context,
) -> JsResult<JsObject> {
let value = &args[0];
let tv = match this_time_value(value, context) {
Ok(dt) => dt.0,
_ => match value.to_primitive(context, PreferredType::Default)? {
JsValue::String(ref str) => match chrono::DateTime::parse_from_rfc3339(str) {
let tv = if let Ok(dt) = this_time_value(value, context) {
dt.0
} else {
let tv = value.to_primitive(context, PreferredType::Default)?;
if let JsVariant::String(ref str) = tv.variant() {
match chrono::DateTime::parse_from_rfc3339(str) {
Ok(dt) => Some(dt.naive_utc()),
_ => None,
},
tv => {
let tv = tv.to_number(context)?;
if tv.is_nan() {
None
} else {
let secs = (tv / 1_000f64) as i64;
let nano_secs = ((tv % 1_000f64) * 1_000_000f64) as u32;
NaiveDateTime::from_timestamp_opt(secs, nano_secs)
}
}
},
} else {
let tv = tv.to_number(context)?;
if tv.is_nan() {
None
} else {
let secs = (tv / 1_000f64) as i64;
let nano_secs = ((tv % 1_000f64) * 1_000_000f64) as u32;
NaiveDateTime::from_timestamp_opt(secs, nano_secs)
}
}
};

let tv = tv.filter(|time| Self::time_clip(time.timestamp_millis() as f64).is_some());
Expand Down Expand Up @@ -522,7 +523,7 @@ impl Date {

let hint = args.get_or_undefined(0);

let try_first = match hint.as_string().map(JsString::as_str) {
let try_first = match hint.as_string().as_ref().map(JsString::as_str) {
// 3. If hint is "string" or "default", then
// a. Let tryFirst be string.
Some("string" | "default") => PreferredType::String,
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/date/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn forward_dt_utc(context: &mut Context, src: &str) -> Option<NaiveDateTime> {
panic!("expected success")
};

if let JsValue::Object(ref date_time) = date_time {
if let Some(ref date_time) = date_time.as_object() {
if let Some(date_time) = date_time.borrow().as_date() {
date_time.0
} else {
Expand Down
1 change: 0 additions & 1 deletion boa/src/builtins/function/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ impl Arguments {
// In the case of duplicate parameter names, the last one is bound as the environment binding.
//
// The following logic implements the steps 17-19 adjusted for our environment structure.

let mut bindings = FxHashMap::default();
let mut property_index = 0;
'outer: for formal in formals {
Expand Down
7 changes: 3 additions & 4 deletions boa/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,7 @@ impl BuiltInFunctionObject {
let target_name = target.get("name", context)?;

// 9. If Type(targetName) is not String, set targetName to the empty String.
let target_name = target_name
.as_string()
.map_or(JsString::new(""), Clone::clone);
let target_name = target_name.as_string().unwrap_or_default();

// 10. Perform SetFunctionName(F, targetName, "bound").
set_function_name(&f, &target_name.into(), Some("bound"), context);
Expand Down Expand Up @@ -425,7 +423,8 @@ impl BuiltInFunctionObject {

#[allow(clippy::wrong_self_convention)]
fn to_string(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let object = this.as_object().map(JsObject::borrow);
let object = this.as_object();
let object = object.as_ref().map(JsObject::borrow);
let function = object
.as_deref()
.and_then(Object::as_function)
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/function/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ fn closure_capture_clone() {
object
.__get_own_property__(&"key".into(), context)?
.and_then(|prop| prop.value().cloned())
.and_then(|val| val.as_string().cloned())
.and_then(|val| val.as_string())
.ok_or_else(|| context.construct_type_error("invalid `key` property"))?,
);
Ok(hw.into())
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/intl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl Intl {
// 1. Let ll be ? CanonicalizeLocaleList(locales).
let ll = Self::canonicalize_locale_list(args, context)?;
// 2. Return CreateArrayFromList(ll).
Ok(JsValue::Object(Array::create_array_from_list(
Ok(JsValue::new(Array::create_array_from_list(
ll.into_iter().map(Into::into),
context,
)))
Expand Down
4 changes: 2 additions & 2 deletions boa/src/builtins/iterable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl JsValue {
// 1. Let syncMethod be ? GetMethod(obj, @@iterator).
let sync_method = self
.get_method(WellKnownSymbols::iterator(), context)?
.map_or(Self::Undefined, Self::from);
.map_or(Self::undefined(), Self::from);
// 2. Let syncIteratorRecord be ? GetIterator(obj, sync, syncMethod).
let _sync_iterator_record =
self.get_iterator(context, Some(IteratorHint::Sync), Some(sync_method));
Expand All @@ -140,7 +140,7 @@ impl JsValue {
} else {
// b. Otherwise, set method to ? GetMethod(obj, @@iterator).
self.get_method(WellKnownSymbols::iterator(), context)?
.map_or(Self::Undefined, Self::from)
.map_or(Self::undefined(), Self::from)
}
};

Expand Down
14 changes: 7 additions & 7 deletions boa/src/builtins/json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ impl Json {
.expect("CreateDataPropertyOrThrow should never throw here");

// d. Return ? InternalizeJSONProperty(root, rootName, reviver).
Self::internalize_json_property(&root, "".into(), obj, context)
Self::internalize_json_property(&root, "".into(), &obj, context)
} else {
// 12. Else,
// a. Return unfiltered.
Expand Down Expand Up @@ -144,7 +144,7 @@ impl Json {
// 1. Let prop be ! ToString(𝔽(I)).
// 2. Let newElement be ? InternalizeJSONProperty(val, prop, reviver).
let new_element = Self::internalize_json_property(
obj,
&obj,
i.to_string().into(),
reviver,
context,
Expand Down Expand Up @@ -176,7 +176,7 @@ impl Json {

// 1. Let newElement be ? InternalizeJSONProperty(val, P, reviver).
let new_element =
Self::internalize_json_property(obj, p.clone(), reviver, context)?;
Self::internalize_json_property(&obj, p.clone(), reviver, context)?;

// 2. If newElement is undefined, then
if new_element.is_undefined() {
Expand Down Expand Up @@ -391,7 +391,7 @@ impl Json {
}

// 4. If Type(value) is Object, then
if let Some(obj) = value.as_object().cloned() {
if let Some(obj) = value.as_object() {
// a. If value has a [[NumberData]] internal slot, then
if obj.is_number() {
// i. Set value to ? ToNumber(value).
Expand Down Expand Up @@ -431,7 +431,7 @@ impl Json {

// 8. If Type(value) is String, return QuoteJSONString(value).
if let Some(s) = value.as_string() {
return Ok(Some(Self::quote_json_string(s)));
return Ok(Some(Self::quote_json_string(&s)));
}

// 9. If Type(value) is Number, then
Expand Down Expand Up @@ -461,9 +461,9 @@ impl Json {
// b. If isArray is true, return ? SerializeJSONArray(state, value).
// c. Return ? SerializeJSONObject(state, value).
return if obj.is_array_abstract(context)? {
Ok(Some(Self::serialize_json_array(state, obj, context)?))
Ok(Some(Self::serialize_json_array(state, &obj, context)?))
} else {
Ok(Some(Self::serialize_json_object(state, obj, context)?))
Ok(Some(Self::serialize_json_object(state, &obj, context)?))
};
}
}
Expand Down
3 changes: 2 additions & 1 deletion boa/src/builtins/map/map_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ impl MapIterator {
///
/// [spec]: https://tc39.es/ecma262/#sec-%mapiteratorprototype%.next
pub(crate) fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut map_iterator = this.as_object().map(JsObject::borrow_mut);
let map_iterator = this.as_object();
let mut map_iterator = map_iterator.as_ref().map(JsObject::borrow_mut);
let map_iterator = map_iterator
.as_mut()
.and_then(|obj| obj.as_map_iterator_mut())
Expand Down
Loading

0 comments on commit 7f71cef

Please sign in to comment.