Skip to content

Commit d3d7fb8

Browse files
committed
Specialized Number, String, Boolean, BigInt, Function objects
- Added helper functions for Object and ValueData - Added `Hash` trait to `Value` - Abstracted Object field access - Deprecated `ObjectInternalMethods`
1 parent 82908df commit d3d7fb8

File tree

21 files changed

+810
-711
lines changed

21 files changed

+810
-711
lines changed

boa/src/builtins/array/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use super::function::{make_builtin_fn, make_constructor_fn};
1616
use crate::{
1717
builtins::{
1818
error::RangeError,
19-
object::{ObjectKind, INSTANCE_PROTOTYPE, PROTOTYPE},
19+
object::{ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE},
2020
property::Property,
2121
value::{same_value_zero, ResultValue, Value, ValueData},
2222
},
@@ -42,7 +42,7 @@ impl Array {
4242
.get_global_object()
4343
.expect("Could not get global object"),
4444
));
45-
array.set_kind(ObjectKind::Array);
45+
array.set_data(ObjectData::Array);
4646
array.borrow().set_internal_slot(
4747
INSTANCE_PROTOTYPE,
4848
interpreter
@@ -117,7 +117,7 @@ impl Array {
117117
this.set_internal_slot(INSTANCE_PROTOTYPE, prototype);
118118
// This value is used by console.log and other routines to match Object type
119119
// to its Javascript Identifier (global constructor method name)
120-
this.set_kind(ObjectKind::Array);
120+
this.set_data(ObjectData::Array);
121121

122122
// add our arguments in
123123
let mut length = args.len() as i32;
@@ -176,7 +176,7 @@ impl Array {
176176
// 1.
177177
ValueData::Object(ref obj) => {
178178
// 2.
179-
if (*obj).deref().borrow().kind == ObjectKind::Array {
179+
if let ObjectData::Array = (*obj).deref().borrow().data {
180180
return Ok(value_true);
181181
}
182182
Ok(value_false)
@@ -1008,7 +1008,7 @@ impl Array {
10081008
let prototype = Value::new_object(None);
10091009
let length = Property::default().value(Value::from(0));
10101010

1011-
prototype.set_property_slice("length", length);
1011+
prototype.set_property("length", length);
10121012

10131013
make_builtin_fn(Self::concat, "concat", &prototype, 1);
10141014
make_builtin_fn(Self::push, "push", &prototype, 1);

boa/src/builtins/bigint/mod.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,11 @@ impl BigInt {
4040
///
4141
/// [spec]: https://tc39.es/ecma262/#sec-bigint-objects
4242
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt
43-
pub(crate) fn make_bigint(
44-
_this: &mut Value,
45-
args: &[Value],
46-
ctx: &mut Interpreter,
47-
) -> ResultValue {
43+
pub(crate) fn make_bigint(_: &mut Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
4844
let data = match args.get(0) {
4945
Some(ref value) => {
5046
if let Some(bigint) = value.to_bigint() {
51-
Value::from(bigint)
47+
bigint
5248
} else {
5349
return Err(RangeError::run_new(
5450
format!(
@@ -59,9 +55,9 @@ impl BigInt {
5955
)?);
6056
}
6157
}
62-
None => Value::from(AstBigInt::from(0)),
58+
None => AstBigInt::from(0),
6359
};
64-
Ok(data)
60+
Ok(Value::from(data))
6561
}
6662

6763
/// `BigInt.prototype.toString( [radix] )`
@@ -119,7 +115,6 @@ impl BigInt {
119115
/// Create a new `Number` object
120116
pub(crate) fn create(global: &Value) -> Value {
121117
let prototype = Value::new_object(Some(global));
122-
prototype.set_internal_slot("BigIntData", Value::from(AstBigInt::from(0)));
123118

124119
make_builtin_fn(Self::to_string, "toString", &prototype, 1);
125120
make_builtin_fn(Self::value_of, "valueOf", &prototype, 0);

boa/src/builtins/boolean/mod.rs

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mod tests;
1515
use super::function::{make_builtin_fn, make_constructor_fn};
1616
use crate::{
1717
builtins::{
18-
object::{internal_methods_trait::ObjectInternalMethods, ObjectKind},
18+
object::ObjectData,
1919
value::{ResultValue, Value, ValueData},
2020
},
2121
exec::Interpreter,
@@ -35,19 +35,11 @@ impl Boolean {
3535
args: &[Value],
3636
_: &mut Interpreter,
3737
) -> ResultValue {
38-
this.set_kind(ObjectKind::Boolean);
39-
4038
// Get the argument, if any
41-
if let Some(ref value) = args.get(0) {
42-
this.set_internal_slot("BooleanData", Self::to_boolean(value));
43-
} else {
44-
this.set_internal_slot("BooleanData", Self::to_boolean(&Value::from(false)));
45-
}
39+
let data = args.get(0).map(|x| x.to_boolean()).unwrap_or(false);
40+
this.set_data(ObjectData::Boolean(data));
4641

47-
match args.get(0) {
48-
Some(ref value) => Ok(Self::to_boolean(value)),
49-
None => Ok(Self::to_boolean(&Value::from(false))),
50-
}
42+
Ok(Value::from(data))
5143
}
5244

5345
/// The `toString()` method returns a string representing the specified `Boolean` object.
@@ -73,22 +65,7 @@ impl Boolean {
7365
/// [spec]: https://tc39.es/ecma262/#sec-boolean.prototype.valueof
7466
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/valueOf
7567
pub(crate) fn value_of(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
76-
Ok(Self::this_boolean_value(this))
77-
}
78-
79-
// === Utility Functions ===
80-
/// [toBoolean](https://tc39.es/ecma262/#sec-toboolean)
81-
/// Creates a new boolean value from the input
82-
#[allow(clippy::wrong_self_convention)]
83-
pub(crate) fn to_boolean(value: &Value) -> Value {
84-
match *value.deref().borrow() {
85-
ValueData::Object(_) => Value::from(true),
86-
ValueData::String(ref s) if !s.is_empty() => Value::from(true),
87-
ValueData::Rational(n) if n != 0.0 && !n.is_nan() => Value::from(true),
88-
ValueData::Integer(n) if n != 0 => Value::from(true),
89-
ValueData::Boolean(v) => Value::from(v),
90-
_ => Value::from(false),
91-
}
68+
Ok(Value::from(Self::this_boolean_value(this)))
9269
}
9370

9471
/// An Utility function used to get the internal BooleanData.
@@ -97,11 +74,14 @@ impl Boolean {
9774
/// - [ECMAScript reference][spec]
9875
///
9976
/// [spec]: https://tc39.es/ecma262/#sec-thisbooleanvalue
100-
pub(crate) fn this_boolean_value(value: &Value) -> Value {
77+
pub(crate) fn this_boolean_value(value: &Value) -> bool {
10178
match *value.deref().borrow() {
102-
ValueData::Boolean(v) => Value::from(v),
103-
ValueData::Object(ref v) => (v).deref().borrow().get_internal_slot("BooleanData"),
104-
_ => Value::from(false),
79+
ValueData::Boolean(v) => v,
80+
ValueData::Object(ref v) => match v.deref().borrow().data {
81+
ObjectData::Boolean(boolean) => boolean,
82+
_ => unreachable!(),
83+
},
84+
_ => false,
10585
}
10686
}
10787

@@ -110,7 +90,6 @@ impl Boolean {
11090
// Create Prototype
11191
// https://tc39.es/ecma262/#sec-properties-of-the-boolean-prototype-object
11292
let prototype = Value::new_object(Some(global));
113-
prototype.set_internal_slot("BooleanData", Self::to_boolean(&Value::from(false)));
11493

11594
make_builtin_fn(Self::to_string, "toString", &prototype, 0);
11695
make_builtin_fn(Self::value_of, "valueOf", &prototype, 0);

boa/src/builtins/error/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use crate::{
1414
builtins::{
1515
function::{make_builtin_fn, make_constructor_fn},
16-
object::ObjectKind,
16+
object::ObjectData,
1717
value::{ResultValue, Value},
1818
},
1919
exec::Interpreter,
@@ -47,7 +47,7 @@ impl Error {
4747
}
4848
// This value is used by console.log and other routines to match Object type
4949
// to its Javascript Identifier (global constructor method name)
50-
this.set_kind(ObjectKind::Error);
50+
this.set_data(ObjectData::Error);
5151
Ok(Value::undefined())
5252
}
5353

boa/src/builtins/error/range.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::{
1313
builtins::{
1414
function::make_builtin_fn,
1515
function::make_constructor_fn,
16-
object::ObjectKind,
16+
object::ObjectData,
1717
value::{ResultValue, Value},
1818
},
1919
exec::Interpreter,
@@ -38,7 +38,7 @@ impl RangeError {
3838
}
3939
// This value is used by console.log and other routines to match Object type
4040
// to its Javascript Identifier (global constructor method name)
41-
this.set_kind(ObjectKind::Error);
41+
this.set_data(ObjectData::Error);
4242
Ok(Value::undefined())
4343
}
4444

boa/src/builtins/function/mod.rs

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use crate::{
1515
builtins::{
1616
array::Array,
17-
object::{Object, ObjectInternalMethods, ObjectKind, INSTANCE_PROTOTYPE, PROTOTYPE},
17+
object::{Object, ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE},
1818
property::Property,
1919
value::{ResultValue, Value},
2020
},
@@ -39,7 +39,7 @@ pub enum ConstructorKind {
3939
/// Defines how this references are interpreted within the formal parameters and code body of the function.
4040
///
4141
/// Arrow functions don't define a `this` and thus are lexical, `function`s do define a this and thus are NonLexical
42-
#[derive(Trace, Finalize, Debug, Clone)]
42+
#[derive(Trace, Finalize, Debug, Clone, PartialEq, PartialOrd, Hash)]
4343
pub enum ThisMode {
4444
Lexical,
4545
NonLexical,
@@ -55,12 +55,24 @@ pub enum FunctionBody {
5555
impl Debug for FunctionBody {
5656
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5757
match self {
58-
Self::BuiltIn(_) => write!(f, "native code"),
58+
Self::BuiltIn(_) => write!(f, "[native]"),
5959
Self::Ordinary(statements) => write!(f, "{:?}", statements),
6060
}
6161
}
6262
}
6363

64+
impl PartialEq for FunctionBody {
65+
fn eq(&self, other: &Self) -> bool {
66+
match (self, other) {
67+
(Self::BuiltIn(a), Self::BuiltIn(b)) => std::ptr::eq(a, b),
68+
(Self::Ordinary(a), Self::Ordinary(b)) => a == b,
69+
(_, _) => false,
70+
}
71+
}
72+
}
73+
74+
impl Eq for FunctionBody {}
75+
6476
/// `Trace` implementation for `FunctionBody`.
6577
///
6678
/// This is indeed safe, but we need to mark this as an empty trace because neither
@@ -158,19 +170,19 @@ impl Function {
158170
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist>
159171
pub fn call(
160172
&self,
161-
this: &mut Value, // represents a pointer to this function object wrapped in a GC (not a `this` JS object)
173+
function: Value, // represents a pointer to this function object wrapped in a GC (not a `this` JS object)
174+
this: &mut Value,
162175
args_list: &[Value],
163176
interpreter: &mut Interpreter,
164-
this_obj: &mut Value,
165177
) -> ResultValue {
166178
if self.callable {
167179
match self.body {
168-
FunctionBody::BuiltIn(func) => func(this_obj, args_list, interpreter),
180+
FunctionBody::BuiltIn(func) => func(this, args_list, interpreter),
169181
FunctionBody::Ordinary(ref body) => {
170182
// Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
171183
// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
172184
let local_env = new_function_environment(
173-
this.clone(),
185+
function,
174186
None,
175187
Some(self.environment.as_ref().unwrap().clone()),
176188
BindingStatus::Uninitialized,
@@ -216,23 +228,23 @@ impl Function {
216228
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget>
217229
pub fn construct(
218230
&self,
219-
this: &mut Value, // represents a pointer to this function object wrapped in a GC (not a `this` JS object)
231+
function: Value, // represents a pointer to this function object wrapped in a GC (not a `this` JS object)
232+
this: &mut Value,
220233
args_list: &[Value],
221234
interpreter: &mut Interpreter,
222-
this_obj: &mut Value,
223235
) -> ResultValue {
224236
if self.constructable {
225237
match self.body {
226238
FunctionBody::BuiltIn(func) => {
227-
func(this_obj, args_list, interpreter).unwrap();
228-
Ok(this_obj.clone())
239+
func(this, args_list, interpreter)?;
240+
Ok(this.clone())
229241
}
230242
FunctionBody::Ordinary(ref body) => {
231243
// Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
232244
// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
233245
let local_env = new_function_environment(
234-
this.clone(),
235-
Some(this_obj.clone()),
246+
function,
247+
Some(this.clone()),
236248
Some(self.environment.as_ref().unwrap().clone()),
237249
BindingStatus::Initialized,
238250
);
@@ -357,7 +369,7 @@ pub fn create_unmapped_arguments_object(arguments_list: &[Value]) -> Value {
357369
.writable(true)
358370
.configurable(true);
359371

360-
obj.properties.insert(index.to_string(), prop);
372+
obj.properties_mut().insert(index.to_string(), prop);
361373
index += 1;
362374
}
363375

@@ -368,7 +380,10 @@ pub fn create_unmapped_arguments_object(arguments_list: &[Value]) -> Value {
368380
///
369381
// This gets called when a new Function() is created.
370382
pub fn make_function(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
371-
this.set_kind(ObjectKind::Function);
383+
this.set_data(ObjectData::Function(Function::builtin(
384+
Vec::new(),
385+
|_, _, _| Ok(Value::undefined()),
386+
)));
372387
Ok(this.clone())
373388
}
374389

@@ -399,8 +414,7 @@ pub fn make_constructor_fn(
399414
let func_prototype = global.get_field("Function").get_field(PROTOTYPE);
400415

401416
// Create the function object and point its instance prototype to Function.prototype
402-
let mut constructor_obj = Object::function();
403-
constructor_obj.set_func(constructor_fn);
417+
let mut constructor_obj = Object::function(constructor_fn);
404418

405419
constructor_obj.set_internal_slot(INSTANCE_PROTOTYPE, func_prototype);
406420
let constructor_val = Value::from(constructor_obj);
@@ -414,14 +428,14 @@ pub fn make_constructor_fn(
414428
.writable(false)
415429
.configurable(false)
416430
.enumerable(false);
417-
constructor_val.set_property_slice("length", length);
431+
constructor_val.set_property("length", length);
418432

419433
let name = Property::new()
420434
.value(Value::from(name))
421435
.writable(false)
422436
.configurable(false)
423437
.enumerable(false);
424-
constructor_val.set_property_slice("name", name);
438+
constructor_val.set_property("name", name);
425439

426440
constructor_val
427441
}
@@ -433,12 +447,9 @@ pub fn make_builtin_fn<N>(function: NativeFunctionData, name: N, parent: &Value,
433447
where
434448
N: Into<String>,
435449
{
436-
let func = Function::builtin(Vec::new(), function);
437-
438-
let mut new_func = Object::function();
439-
new_func.set_func(func);
450+
let func = Object::function(Function::builtin(Vec::new(), function));
440451

441-
let new_func_obj = Value::from(new_func);
452+
let new_func_obj = Value::from(func);
442453
new_func_obj.set_field("length", length);
443454

444455
parent.set_field(name.into(), new_func_obj);

boa/src/builtins/json/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
1616
use crate::builtins::{
1717
function::make_builtin_fn,
18-
object::ObjectKind,
1918
property::Property,
2019
value::{ResultValue, Value},
2120
};
@@ -87,7 +86,7 @@ pub fn stringify(_: &mut Value, args: &[Value], interpreter: &mut Interpreter) -
8786
.map(|obj| {
8887
let object_to_return = Value::new_object(None);
8988
for (key, val) in obj
90-
.properties
89+
.properties()
9190
.iter()
9291
.filter_map(|(k, v)| v.value.as_ref().map(|value| (k, value)))
9392
{
@@ -104,10 +103,10 @@ pub fn stringify(_: &mut Value, args: &[Value], interpreter: &mut Interpreter) -
104103
Ok(Value::from(object_to_return.to_json().to_string()))
105104
})
106105
.ok_or_else(Value::undefined)?
107-
} else if replacer_as_object.kind == ObjectKind::Array {
106+
} else if replacer_as_object.is_array() {
108107
let mut obj_to_return =
109-
serde_json::Map::with_capacity(replacer_as_object.properties.len() - 1);
110-
let fields = replacer_as_object.properties.keys().filter_map(|key| {
108+
serde_json::Map::with_capacity(replacer_as_object.properties().len() - 1);
109+
let fields = replacer_as_object.properties().keys().filter_map(|key| {
111110
if key == "length" {
112111
None
113112
} else {

0 commit comments

Comments
 (0)