From 8daf6b7eb1fdbac1ac89af7db247d6377c6efea6 Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Mon, 25 May 2020 22:53:08 +0200 Subject: [PATCH 1/4] Specialized Number, String and Boolean objects --- boa/src/builtins/array/mod.rs | 8 +-- boa/src/builtins/boolean/mod.rs | 45 ++++--------- boa/src/builtins/error/mod.rs | 4 +- boa/src/builtins/error/range.rs | 4 +- boa/src/builtins/function/mod.rs | 4 +- boa/src/builtins/number/mod.rs | 28 ++++---- boa/src/builtins/object/mod.rs | 107 ++++++++++--------------------- boa/src/builtins/regexp/mod.rs | 6 +- boa/src/builtins/string/mod.rs | 26 ++------ boa/src/builtins/symbol/mod.rs | 4 +- boa/src/builtins/value/mod.rs | 45 +++++++------ boa/src/exec/mod.rs | 35 +++++----- 12 files changed, 127 insertions(+), 189 deletions(-) diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 4cf03d37901..2f79c7ce4ac 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -16,7 +16,7 @@ use super::function::{make_builtin_fn, make_constructor_fn}; use crate::{ builtins::{ error::RangeError, - object::{ObjectKind, INSTANCE_PROTOTYPE, PROTOTYPE}, + object::{ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE}, property::Property, value::{same_value_zero, ResultValue, Value, ValueData}, }, @@ -42,7 +42,7 @@ impl Array { .get_global_object() .expect("Could not get global object"), )); - array.set_kind(ObjectKind::Array); + array.set_data(ObjectData::Array); array.borrow().set_internal_slot( INSTANCE_PROTOTYPE, interpreter @@ -117,7 +117,7 @@ impl Array { this.set_internal_slot(INSTANCE_PROTOTYPE, prototype); // This value is used by console.log and other routines to match Object type // to its Javascript Identifier (global constructor method name) - this.set_kind(ObjectKind::Array); + this.set_data(ObjectData::Array); // add our arguments in let mut length = args.len() as i32; @@ -176,7 +176,7 @@ impl Array { // 1. ValueData::Object(ref obj) => { // 2. - if (*obj).deref().borrow().kind == ObjectKind::Array { + if (*obj).deref().borrow().data == ObjectData::Array { return Ok(value_true); } Ok(value_false) diff --git a/boa/src/builtins/boolean/mod.rs b/boa/src/builtins/boolean/mod.rs index 40b7de056dd..f8895ae2816 100644 --- a/boa/src/builtins/boolean/mod.rs +++ b/boa/src/builtins/boolean/mod.rs @@ -15,7 +15,7 @@ mod tests; use super::function::{make_builtin_fn, make_constructor_fn}; use crate::{ builtins::{ - object::{internal_methods_trait::ObjectInternalMethods, ObjectKind}, + object::ObjectData, value::{ResultValue, Value, ValueData}, }, exec::Interpreter, @@ -35,19 +35,11 @@ impl Boolean { args: &[Value], _: &mut Interpreter, ) -> ResultValue { - this.set_kind(ObjectKind::Boolean); - // Get the argument, if any - if let Some(ref value) = args.get(0) { - this.set_internal_slot("BooleanData", Self::to_boolean(value)); - } else { - this.set_internal_slot("BooleanData", Self::to_boolean(&Value::from(false))); - } + let data = args.get(0).map(|x| x.to_boolean()).unwrap_or(false); + this.set_data(ObjectData::Boolean(data)); - match args.get(0) { - Some(ref value) => Ok(Self::to_boolean(value)), - None => Ok(Self::to_boolean(&Value::from(false))), - } + Ok(Value::from(data)) } /// The `toString()` method returns a string representing the specified `Boolean` object. @@ -73,22 +65,7 @@ impl Boolean { /// [spec]: https://tc39.es/ecma262/#sec-boolean.prototype.valueof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/valueOf pub(crate) fn value_of(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue { - Ok(Self::this_boolean_value(this)) - } - - // === Utility Functions === - /// [toBoolean](https://tc39.es/ecma262/#sec-toboolean) - /// Creates a new boolean value from the input - #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_boolean(value: &Value) -> Value { - match *value.deref().borrow() { - ValueData::Object(_) => Value::from(true), - ValueData::String(ref s) if !s.is_empty() => Value::from(true), - ValueData::Rational(n) if n != 0.0 && !n.is_nan() => Value::from(true), - ValueData::Integer(n) if n != 0 => Value::from(true), - ValueData::Boolean(v) => Value::from(v), - _ => Value::from(false), - } + Ok(Value::from(Self::this_boolean_value(this))) } /// An Utility function used to get the internal BooleanData. @@ -97,11 +74,14 @@ impl Boolean { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-thisbooleanvalue - pub(crate) fn this_boolean_value(value: &Value) -> Value { + pub(crate) fn this_boolean_value(value: &Value) -> bool { match *value.deref().borrow() { - ValueData::Boolean(v) => Value::from(v), - ValueData::Object(ref v) => (v).deref().borrow().get_internal_slot("BooleanData"), - _ => Value::from(false), + ValueData::Boolean(v) => v, + ValueData::Object(ref v) => match v.deref().borrow().data { + ObjectData::Boolean(boolean) => boolean, + _ => unreachable!(), + }, + _ => false, } } @@ -110,7 +90,6 @@ impl Boolean { // Create Prototype // https://tc39.es/ecma262/#sec-properties-of-the-boolean-prototype-object let prototype = Value::new_object(Some(global)); - prototype.set_internal_slot("BooleanData", Self::to_boolean(&Value::from(false))); make_builtin_fn(Self::to_string, "toString", &prototype, 0); make_builtin_fn(Self::value_of, "valueOf", &prototype, 0); diff --git a/boa/src/builtins/error/mod.rs b/boa/src/builtins/error/mod.rs index 328edc50bfb..bea435ea65b 100644 --- a/boa/src/builtins/error/mod.rs +++ b/boa/src/builtins/error/mod.rs @@ -13,7 +13,7 @@ use crate::{ builtins::{ function::{make_builtin_fn, make_constructor_fn}, - object::ObjectKind, + object::ObjectData, value::{ResultValue, Value}, }, exec::Interpreter, @@ -47,7 +47,7 @@ impl Error { } // This value is used by console.log and other routines to match Object type // to its Javascript Identifier (global constructor method name) - this.set_kind(ObjectKind::Error); + this.set_data(ObjectData::Error); Ok(Value::undefined()) } diff --git a/boa/src/builtins/error/range.rs b/boa/src/builtins/error/range.rs index 34e4c88ff77..1fc3789219c 100644 --- a/boa/src/builtins/error/range.rs +++ b/boa/src/builtins/error/range.rs @@ -13,7 +13,7 @@ use crate::{ builtins::{ function::make_builtin_fn, function::make_constructor_fn, - object::ObjectKind, + object::ObjectData, value::{ResultValue, Value}, }, exec::Interpreter, @@ -38,7 +38,7 @@ impl RangeError { } // This value is used by console.log and other routines to match Object type // to its Javascript Identifier (global constructor method name) - this.set_kind(ObjectKind::Error); + this.set_data(ObjectData::Error); Ok(Value::undefined()) } diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index 2886b97051f..f16355e4ada 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -14,7 +14,7 @@ use crate::{ builtins::{ array::Array, - object::{Object, ObjectInternalMethods, ObjectKind, INSTANCE_PROTOTYPE, PROTOTYPE}, + object::{Object, ObjectData, ObjectInternalMethods, INSTANCE_PROTOTYPE, PROTOTYPE}, property::Property, value::{ResultValue, Value}, }, @@ -368,7 +368,7 @@ pub fn create_unmapped_arguments_object(arguments_list: &[Value]) -> Value { /// // This gets called when a new Function() is created. pub fn make_function(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue { - this.set_kind(ObjectKind::Function); + this.set_data(ObjectData::Function); Ok(this.clone()) } diff --git a/boa/src/builtins/number/mod.rs b/boa/src/builtins/number/mod.rs index 05cde1dcf13..06e9bddfd83 100644 --- a/boa/src/builtins/number/mod.rs +++ b/boa/src/builtins/number/mod.rs @@ -18,18 +18,17 @@ mod tests; use super::{ function::{make_builtin_fn, make_constructor_fn}, - object::ObjectKind, + object::ObjectData, }; use crate::{ builtins::{ - object::internal_methods_trait::ObjectInternalMethods, value::{ResultValue, Value, ValueData}, RangeError, }, exec::Interpreter, }; use num_traits::float::FloatCore; -use std::{borrow::Borrow, f64, ops::Deref}; +use std::{f64, ops::Deref}; const BUF_SIZE: usize = 2200; @@ -41,19 +40,22 @@ impl Number { /// Helper function that converts a Value to a Number. #[allow(clippy::wrong_self_convention)] fn to_number(value: &Value) -> Value { - match *value.deref().borrow() { + match value.data() { ValueData::Boolean(b) => { - if b { + if *b { Value::from(1) } else { Value::from(0) } } ValueData::Symbol(_) | ValueData::Undefined => Value::from(f64::NAN), - ValueData::Integer(i) => Value::from(f64::from(i)), - ValueData::Object(ref o) => (o).deref().borrow().get_internal_slot("NumberData"), + ValueData::Integer(i) => Value::from(f64::from(*i)), + ValueData::Object(ref o) => match (o).deref().borrow().data { + ObjectData::Number(num) => Value::from(num), + _ => unreachable!(), + }, ValueData::Null => Value::from(0), - ValueData::Rational(n) => Value::from(n), + ValueData::Rational(n) => Value::from(*n), ValueData::BigInt(ref bigint) => Value::from(bigint.to_f64()), ValueData::String(ref s) => match s.parse::() { Ok(n) => Value::from(n), @@ -80,13 +82,12 @@ impl Number { _ctx: &mut Interpreter, ) -> ResultValue { let data = match args.get(0) { - Some(ref value) => Self::to_number(value), - None => Self::to_number(&Value::from(0)), + Some(ref value) => Self::to_number(value).to_number(), + None => 0.0, }; - this.set_kind(ObjectKind::Number); - this.set_internal_slot("NumberData", data.clone()); + this.set_data(ObjectData::Number(data)); - Ok(data) + Ok(Value::from(data)) } /// `Number.prototype.toExponential( [fractionDigits] )` @@ -393,7 +394,6 @@ impl Number { /// Create a new `Number` object pub(crate) fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - prototype.set_internal_slot("NumberData", Value::from(0)); make_builtin_fn(Self::to_exponential, "toExponential", &prototype, 1); make_builtin_fn(Self::to_fixed, "toFixed", &prototype, 1); diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 912d15203cd..5fae2778f37 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -21,11 +21,10 @@ use crate::{ }, exec::Interpreter, }; -use gc::{unsafe_empty_trace, Finalize, Trace}; +use gc::{Finalize, Trace}; use rustc_hash::FxHashMap; use std::{ - borrow::Borrow, - fmt::{self, Debug, Display, Error, Formatter}, + fmt::{Debug, Display, Error, Formatter}, ops::Deref, }; @@ -43,10 +42,10 @@ pub static PROTOTYPE: &str = "prototype"; pub static INSTANCE_PROTOTYPE: &str = "__proto__"; /// The internal representation of an JavaScript object. -#[derive(Trace, Finalize, Clone)] +#[derive(Debug, Trace, Finalize, Clone)] pub struct Object { /// The type of the object. - pub kind: ObjectKind, + pub data: ObjectData, /// Internal Slots pub internal_slots: FxHashMap, /// Properties @@ -59,21 +58,6 @@ pub struct Object { pub func: Option, } -impl Debug for Object { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - writeln!(f, "{{")?; - writeln!(f, "\tkind: {}", self.kind)?; - writeln!(f, "\tstate: {:?}", self.state)?; - writeln!(f, "\tfunc: {:?}", self.func)?; - writeln!(f, "\tproperties: {{")?; - for (key, _) in self.properties.iter() { - writeln!(f, "\t\t{}", key)?; - } - writeln!(f, "\t }}")?; - write!(f, "}}") - } -} - impl ObjectInternalMethods for Object { /// `Object.setPropertyOf(obj, prototype)` /// @@ -335,7 +319,7 @@ impl Object { /// Return a new ObjectData struct, with `kind` set to Ordinary pub fn default() -> Self { let mut object = Self { - kind: ObjectKind::Ordinary, + data: ObjectData::Ordinary, internal_slots: FxHashMap::default(), properties: FxHashMap::default(), sym_properties: FxHashMap::default(), @@ -350,7 +334,7 @@ impl Object { /// Return a new ObjectData struct, with `kind` set to Ordinary pub fn function() -> Self { let mut object = Self { - kind: ObjectKind::Function, + data: ObjectData::Function, internal_slots: FxHashMap::default(), properties: FxHashMap::default(), sym_properties: FxHashMap::default(), @@ -384,57 +368,45 @@ impl Object { } /// Return a new Boolean object whose `[[BooleanData]]` internal slot is set to argument. - fn from_boolean(argument: &Value) -> Self { - let mut obj = Self { - kind: ObjectKind::Boolean, + fn from_boolean(value: bool) -> Self { + Self { + data: ObjectData::Boolean(value), internal_slots: FxHashMap::default(), properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, func: None, - }; - - obj.internal_slots - .insert("BooleanData".to_string(), argument.clone()); - obj + } } /// Return a new `Number` object whose `[[NumberData]]` internal slot is set to argument. - fn from_number(argument: &Value) -> Self { - let mut obj = Self { - kind: ObjectKind::Number, + fn from_number(value: f64) -> Self { + Self { + data: ObjectData::Number(value), internal_slots: FxHashMap::default(), properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, func: None, - }; - - obj.internal_slots - .insert("NumberData".to_string(), argument.clone()); - obj + } } /// Return a new `String` object whose `[[StringData]]` internal slot is set to argument. - fn from_string(argument: &Value) -> Self { - let mut obj = Self { - kind: ObjectKind::String, + fn from_string(value: String) -> Self { + Self { + data: ObjectData::String(value), internal_slots: FxHashMap::default(), properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, func: None, - }; - - obj.internal_slots - .insert("StringData".to_string(), argument.clone()); - obj + } } /// Return a new `BigInt` object whose `[[BigIntData]]` internal slot is set to argument. fn from_bigint(argument: &Value) -> Self { let mut obj = Self { - kind: ObjectKind::BigInt, + data: ObjectData::BigInt, internal_slots: FxHashMap::default(), properties: FxHashMap::default(), sym_properties: FxHashMap::default(), @@ -454,10 +426,11 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-toobject pub fn from(value: &Value) -> Result { - match *value.deref().borrow() { - ValueData::Boolean(_) => Ok(Self::from_boolean(value)), - ValueData::Rational(_) => Ok(Self::from_number(value)), - ValueData::String(_) => Ok(Self::from_string(value)), + match *value.data() { + ValueData::Boolean(a) => Ok(Self::from_boolean(a)), + ValueData::Rational(a) => Ok(Self::from_number(a)), + ValueData::Integer(a) => Ok(Self::from_number(f64::from(a))), + ValueData::String(ref a) => Ok(Self::from_string(a.clone())), ValueData::BigInt(_) => Ok(Self::from_bigint(value)), ValueData::Object(ref obj) => Ok((*obj).deref().borrow().clone()), _ => Err(()), @@ -492,20 +465,20 @@ impl Object { } /// Defines the different types of objects. -#[derive(Finalize, Debug, Copy, Clone, Eq, PartialEq)] -pub enum ObjectKind { +#[derive(Debug, Trace, Finalize, Clone, PartialEq)] +pub enum ObjectData { Function, Array, - String, + String(String), Symbol, Error, - Ordinary, - Boolean, - Number, + Boolean(bool), + Number(f64), BigInt, + Ordinary, } -impl Display for ObjectKind { +impl Display for ObjectData { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { write!( f, @@ -513,30 +486,18 @@ impl Display for ObjectKind { match self { Self::Function => "Function", Self::Array => "Array", - Self::String => "String", + Self::String(_) => "String", Self::Symbol => "Symbol", Self::Error => "Error", Self::Ordinary => "Ordinary", - Self::Boolean => "Boolean", - Self::Number => "Number", + Self::Boolean(_) => "Boolean", + Self::Number(_) => "Number", Self::BigInt => "BigInt", } ) } } -/// `Trace` implementation for `ObjectKind`. -/// -/// This is indeed safe, but we need to mark this as an empty trace because neither -// `NativeFunctionData` nor Node hold any GC'd objects, but Gc doesn't know that. So we need to -/// signal it manually. `rust-gc` does not have a `Trace` implementation for `fn(_, _, _)`. -/// -/// -/// Waiting on until we can derive Copy -unsafe impl Trace for ObjectKind { - unsafe_empty_trace!(); -} - /// Create a new object. pub fn make_object(_: &mut Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(arg) = args.get(0) { diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index af82d3bfe80..4d333f90482 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -16,7 +16,7 @@ use regex::Regex; use super::function::{make_builtin_fn, make_constructor_fn}; use crate::{ builtins::{ - object::{InternalState, ObjectKind}, + object::{InternalState, ObjectData}, property::Property, value::{ResultValue, Value, ValueData}, }, @@ -159,7 +159,7 @@ impl RegExp { // This value is used by console.log and other routines to match Object type // to its Javascript Identifier (global constructor method name) - this.set_kind(ObjectKind::Ordinary); + this.set_data(ObjectData::Ordinary); this.set_internal_slot("RegExpMatcher", Value::undefined()); this.set_internal_slot("OriginalSource", Value::from(regex_body)); this.set_internal_slot("OriginalFlags", Value::from(regex_flags)); @@ -462,7 +462,7 @@ impl RegExp { let length = matches.len(); let result = Value::from(matches); result.set_field("length", Value::from(length)); - result.set_kind(ObjectKind::Array); + result.set_data(ObjectData::Array); Ok(result) } diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index 06ba55460b1..dee862feb6b 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -15,7 +15,7 @@ mod tests; use super::function::{make_builtin_fn, make_constructor_fn}; use crate::{ builtins::{ - object::{Object, ObjectKind}, + object::{Object, ObjectData}, property::Property, value::{ResultValue, Value, ValueData}, RegExp, @@ -46,32 +46,20 @@ impl String { ) -> ResultValue { // This value is used by console.log and other routines to match Obexpecty"failed to parse argument for String method"pe // to its Javascript Identifier (global constructor method name) - let s = args.get(0).unwrap_or(&Value::string("")).clone(); - let length_str = s.to_string().chars().count(); + let string = args.get(0).map(|x| x.to_string()).unwrap_or_default(); + let length = string.chars().count(); - this.set_field("length", Value::from(length_str as i32)); + this.set_field("length", Value::from(length as i32)); - this.set_kind(ObjectKind::String); - this.set_internal_slot("StringData", s); + this.set_data(ObjectData::String(string.clone())); - let arg = match args.get(0) { - Some(v) => v.clone(), - None => Value::undefined(), - }; - - if arg.is_undefined() { - return Ok("".into()); - } - - Ok(Value::from(arg.to_string())) + Ok(Value::from(string)) } /// Get the string value to a primitive string #[allow(clippy::wrong_self_convention)] pub(crate) fn to_string(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue { - // Get String from String Object and send it back as a new value - let primitive_val = this.get_internal_slot("StringData"); - Ok(Value::from(format!("{}", primitive_val))) + Ok(Value::from(this.to_string())) } /// `String.prototype.charAt( index )` diff --git a/boa/src/builtins/symbol/mod.rs b/boa/src/builtins/symbol/mod.rs index e71a5dc09c3..9fd53fae84b 100644 --- a/boa/src/builtins/symbol/mod.rs +++ b/boa/src/builtins/symbol/mod.rs @@ -22,7 +22,7 @@ use super::function::{make_builtin_fn, make_constructor_fn}; use crate::{ builtins::{ object::{ - internal_methods_trait::ObjectInternalMethods, Object, ObjectKind, INSTANCE_PROTOTYPE, + internal_methods_trait::ObjectInternalMethods, Object, ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE, }, value::{ResultValue, Value, ValueData}, @@ -48,7 +48,7 @@ pub fn call_symbol(_: &mut Value, args: &[Value], ctx: &mut Interpreter) -> Resu // So we start by creating an Object // TODO: Set prototype to Symbol.prototype (by changing to Object::create(), use interpreter to get Symbol.prototype) let mut sym_instance = Object::default(); - sym_instance.kind = ObjectKind::Symbol; + sym_instance.data = ObjectData::Symbol; // Set description which should either be undefined or a string let desc_string = match args.get(0) { diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 0d3f86672cb..99016633b70 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -9,7 +9,7 @@ use crate::builtins::{ function::Function, object::{ internal_methods_trait::ObjectInternalMethods, InternalState, InternalStateCell, Object, - ObjectKind, INSTANCE_PROTOTYPE, PROTOTYPE, + ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE, }, property::Property, }; @@ -133,9 +133,9 @@ impl Value { } /// Similar to `new_object`, but you can pass a prototype to create from, plus a kind - pub fn new_object_from_prototype(proto: Value, kind: ObjectKind) -> Self { + pub fn new_object_from_prototype(proto: Value, data: ObjectData) -> Self { let mut object = Object::default(); - object.kind = kind; + object.data = data; object .internal_slots @@ -364,7 +364,7 @@ impl ValueData { ValueData::BigInt(b) => Some(b.clone()), ValueData::Object(ref o) => { let object = (o).deref().borrow(); - if object.kind == ObjectKind::BigInt { + if object.data == ObjectData::BigInt { object.get_internal_slot("BigIntData").to_bigint() } else { None @@ -374,6 +374,20 @@ impl ValueData { } } + /// Creates a new boolean value from the input + pub fn to_boolean(&self) -> bool { + match *self { + Self::Undefined | Self::Null => false, + Self::Symbol(_) | Self::Object(_) => true, + Self::String(ref s) if !s.is_empty() => true, + Self::Rational(n) if n != 0.0 && !n.is_nan() => true, + Self::Integer(n) if n != 0 => true, + Self::BigInt(ref n) if *n != 0 => true, + Self::Boolean(v) => v, + _ => false, + } + } + pub fn as_object(&self) -> Option> { match *self { ValueData::Object(ref o) => Some(o.borrow()), @@ -600,7 +614,7 @@ impl ValueData { let val = val.into(); if let Self::Object(ref obj) = *self { - if obj.borrow().kind == ObjectKind::Array { + if obj.borrow().data == ObjectData::Array { if let Ok(num) = field.to_string().parse::() { if num > 0 { let len = i32::from(&self.get_field("length")); @@ -634,9 +648,9 @@ impl ValueData { } /// Set the kind of an object - pub fn set_kind(&self, kind: ObjectKind) { + pub fn set_data(&self, data: ObjectData) { if let Self::Object(ref obj) = *self { - (*obj.deref().borrow_mut()).kind = kind; + (*obj.deref().borrow_mut()).data = data; } } @@ -836,19 +850,10 @@ pub(crate) fn log_string_from(x: &ValueData, print_internals: bool) -> String { ValueData::Object(ref v) => { // Can use the private "type" field of an Object to match on // which type of Object it represents for special printing - match v.borrow().kind { - ObjectKind::String => String::from( - v.borrow() - .internal_slots - .get("StringData") - .expect("Cannot get primitive value from String"), - ), - ObjectKind::Boolean => { - let bool_data = v.borrow().get_internal_slot("BooleanData").to_string(); - - format!("Boolean {{ {} }}", bool_data) - } - ObjectKind::Array => { + match v.borrow().data { + ObjectData::String(ref string) => string.clone(), + ObjectData::Boolean(boolean) => format!("Boolean {{ {} }}", boolean), + ObjectData::Array => { let len = i32::from( &v.borrow() .properties diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 4f0c8266818..93e99bcf170 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -15,7 +15,7 @@ use crate::{ builtins::{ function::{Function as FunctionObject, FunctionBody, ThisMode}, object::{ - internal_methods_trait::ObjectInternalMethods, Object, ObjectKind, INSTANCE_PROTOTYPE, + internal_methods_trait::ObjectInternalMethods, Object, ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE, }, property::Property, @@ -151,7 +151,7 @@ impl Interpreter { pub(crate) fn extract_array_properties(&mut self, value: &Value) -> Result, ()> { if let ValueData::Object(ref x) = *value.deref().borrow() { // Check if object is array - if x.deref().borrow().kind == ObjectKind::Array { + if x.deref().borrow().data == ObjectData::Array { let length: i32 = self.value_to_rust_number(&value.get_field("length")) as i32; let values: Vec = (0..length) .map(|idx| value.get_field(idx.to_string())) @@ -281,36 +281,41 @@ impl Interpreter { ValueData::Undefined | ValueData::Integer(_) | ValueData::Null => { Err(Value::undefined()) } - ValueData::Boolean(_) => { + ValueData::Boolean(boolean) => { let proto = self .realm .environment .get_binding_value("Boolean") .get_field(PROTOTYPE); - let bool_obj = Value::new_object_from_prototype(proto, ObjectKind::Boolean); - bool_obj.set_internal_slot("BooleanData", value.clone()); - Ok(bool_obj) + Ok(Value::new_object_from_prototype( + proto, + ObjectData::Boolean(boolean), + )) } - ValueData::Rational(_) => { + ValueData::Rational(rational) => { let proto = self .realm .environment .get_binding_value("Number") .get_field(PROTOTYPE); - let number_obj = Value::new_object_from_prototype(proto, ObjectKind::Number); - number_obj.set_internal_slot("NumberData", value.clone()); - Ok(number_obj) + + Ok(Value::new_object_from_prototype( + proto, + ObjectData::Number(rational), + )) } - ValueData::String(_) => { + ValueData::String(ref string) => { let proto = self .realm .environment .get_binding_value("String") .get_field(PROTOTYPE); - let string_obj = Value::new_object_from_prototype(proto, ObjectKind::String); - string_obj.set_internal_slot("StringData", value.clone()); - Ok(string_obj) + + Ok(Value::new_object_from_prototype( + proto, + ObjectData::String(string.clone()), + )) } ValueData::Object(_) | ValueData::Symbol(_) => Ok(value.clone()), ValueData::BigInt(_) => { @@ -319,7 +324,7 @@ impl Interpreter { .environment .get_binding_value("BigInt") .get_field(PROTOTYPE); - let bigint_obj = Value::new_object_from_prototype(proto, ObjectKind::BigInt); + let bigint_obj = Value::new_object_from_prototype(proto, ObjectData::BigInt); bigint_obj.set_internal_slot("BigIntData", value.clone()); Ok(bigint_obj) } From a1fa22e59bcfd29d49a00bba8289186844561a3f Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Tue, 26 May 2020 18:37:30 +0200 Subject: [PATCH 2/4] Some call and construct cleanup --- boa/src/builtins/function/mod.rs | 22 +++++++++++----------- boa/src/builtins/object/mod.rs | 18 +++++++++--------- boa/src/exec/expression/mod.rs | 4 ++-- boa/src/exec/mod.rs | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index f16355e4ada..f77969c6df5 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -55,7 +55,7 @@ pub enum FunctionBody { impl Debug for FunctionBody { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::BuiltIn(_) => write!(f, "native code"), + Self::BuiltIn(_) => write!(f, "[native]"), Self::Ordinary(statements) => write!(f, "{:?}", statements), } } @@ -158,19 +158,19 @@ impl Function { /// pub fn call( &self, - this: &mut Value, // represents a pointer to this function object wrapped in a GC (not a `this` JS object) + function: Value, // represents a pointer to this function object wrapped in a GC (not a `this` JS object) + this: &mut Value, args_list: &[Value], interpreter: &mut Interpreter, - this_obj: &mut Value, ) -> ResultValue { if self.callable { match self.body { - FunctionBody::BuiltIn(func) => func(this_obj, args_list, interpreter), + FunctionBody::BuiltIn(func) => func(this, args_list, interpreter), FunctionBody::Ordinary(ref body) => { // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment) // let local_env = new_function_environment( - this.clone(), + function, None, Some(self.environment.as_ref().unwrap().clone()), BindingStatus::Uninitialized, @@ -216,23 +216,23 @@ impl Function { /// pub fn construct( &self, - this: &mut Value, // represents a pointer to this function object wrapped in a GC (not a `this` JS object) + function: Value, // represents a pointer to this function object wrapped in a GC (not a `this` JS object) + this: &mut Value, args_list: &[Value], interpreter: &mut Interpreter, - this_obj: &mut Value, ) -> ResultValue { if self.constructable { match self.body { FunctionBody::BuiltIn(func) => { - func(this_obj, args_list, interpreter).unwrap(); - Ok(this_obj.clone()) + func(this, args_list, interpreter)?; + Ok(this.clone()) } FunctionBody::Ordinary(ref body) => { // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment) // let local_env = new_function_environment( - this.clone(), - Some(this_obj.clone()), + function, + Some(this.clone()), Some(self.environment.as_ref().unwrap().clone()), BindingStatus::Initialized, ); diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 5fae2778f37..d22ad1477dc 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -368,7 +368,7 @@ impl Object { } /// Return a new Boolean object whose `[[BooleanData]]` internal slot is set to argument. - fn from_boolean(value: bool) -> Self { + pub fn boolean(value: bool) -> Self { Self { data: ObjectData::Boolean(value), internal_slots: FxHashMap::default(), @@ -380,7 +380,7 @@ impl Object { } /// Return a new `Number` object whose `[[NumberData]]` internal slot is set to argument. - fn from_number(value: f64) -> Self { + pub fn number(value: f64) -> Self { Self { data: ObjectData::Number(value), internal_slots: FxHashMap::default(), @@ -392,7 +392,7 @@ impl Object { } /// Return a new `String` object whose `[[StringData]]` internal slot is set to argument. - fn from_string(value: String) -> Self { + pub fn string(value: String) -> Self { Self { data: ObjectData::String(value), internal_slots: FxHashMap::default(), @@ -404,7 +404,7 @@ impl Object { } /// Return a new `BigInt` object whose `[[BigIntData]]` internal slot is set to argument. - fn from_bigint(argument: &Value) -> Self { + pub fn bigint(argument: &Value) -> Self { let mut obj = Self { data: ObjectData::BigInt, internal_slots: FxHashMap::default(), @@ -427,11 +427,11 @@ impl Object { /// [spec]: https://tc39.es/ecma262/#sec-toobject pub fn from(value: &Value) -> Result { match *value.data() { - ValueData::Boolean(a) => Ok(Self::from_boolean(a)), - ValueData::Rational(a) => Ok(Self::from_number(a)), - ValueData::Integer(a) => Ok(Self::from_number(f64::from(a))), - ValueData::String(ref a) => Ok(Self::from_string(a.clone())), - ValueData::BigInt(_) => Ok(Self::from_bigint(value)), + ValueData::Boolean(a) => Ok(Self::boolean(a)), + ValueData::Rational(a) => Ok(Self::number(a)), + ValueData::Integer(a) => Ok(Self::number(f64::from(a))), + ValueData::String(ref a) => Ok(Self::string(a.clone())), + ValueData::BigInt(_) => Ok(Self::bigint(value)), ValueData::Object(ref obj) => Ok((*obj).deref().borrow().clone()), _ => Err(()), } diff --git a/boa/src/exec/expression/mod.rs b/boa/src/exec/expression/mod.rs index 57fc661ca7a..7eb72bef594 100644 --- a/boa/src/exec/expression/mod.rs +++ b/boa/src/exec/expression/mod.rs @@ -70,10 +70,10 @@ impl Executable for New { match func_object.data() { ValueData::Object(ref o) => o.clone().borrow_mut().func.as_ref().unwrap().construct( - &mut func_object.clone(), + func_object.clone(), + &mut this, &v_args, interpreter, - &mut this, ), _ => Ok(Value::undefined()), } diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 93e99bcf170..f4780a12860 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -123,7 +123,7 @@ impl Interpreter { ValueData::Object(ref obj) => { let obj = (**obj).borrow(); let func = obj.func.as_ref().expect("Expected function"); - func.call(&mut f.clone(), arguments_list, self, this) + func.call(f.clone(), this, arguments_list, self) } _ => Err(Value::undefined()), } From 5c4dc6faa8f85ee8c757c5f4f35846a7cdee25e4 Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Tue, 26 May 2020 19:03:28 +0200 Subject: [PATCH 3/4] Added specialization for BigInt --- boa/src/builtins/bigint/mod.rs | 13 ++++--------- boa/src/builtins/object/mod.rs | 19 ++++++++----------- boa/src/builtins/value/mod.rs | 4 ++-- boa/src/exec/mod.rs | 6 +++--- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/boa/src/builtins/bigint/mod.rs b/boa/src/builtins/bigint/mod.rs index f01b4573c6a..b2206b8fb7f 100644 --- a/boa/src/builtins/bigint/mod.rs +++ b/boa/src/builtins/bigint/mod.rs @@ -40,15 +40,11 @@ impl BigInt { /// /// [spec]: https://tc39.es/ecma262/#sec-bigint-objects /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt - pub(crate) fn make_bigint( - _this: &mut Value, - args: &[Value], - ctx: &mut Interpreter, - ) -> ResultValue { + pub(crate) fn make_bigint(_: &mut Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { let data = match args.get(0) { Some(ref value) => { if let Some(bigint) = value.to_bigint() { - Value::from(bigint) + bigint } else { return Err(RangeError::run_new( format!( @@ -59,9 +55,9 @@ impl BigInt { )?); } } - None => Value::from(AstBigInt::from(0)), + None => AstBigInt::from(0), }; - Ok(data) + Ok(Value::from(data)) } /// `BigInt.prototype.toString( [radix] )` @@ -119,7 +115,6 @@ impl BigInt { /// Create a new `Number` object pub(crate) fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - prototype.set_internal_slot("BigIntData", Value::from(AstBigInt::from(0))); make_builtin_fn(Self::to_string, "toString", &prototype, 1); make_builtin_fn(Self::value_of, "valueOf", &prototype, 0); diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index d22ad1477dc..980882505f7 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -20,6 +20,7 @@ use crate::{ value::{same_value, ResultValue, Value, ValueData}, }, exec::Interpreter, + syntax::ast::bigint::BigInt as AstBigInt, }; use gc::{Finalize, Trace}; use rustc_hash::FxHashMap; @@ -404,19 +405,15 @@ impl Object { } /// Return a new `BigInt` object whose `[[BigIntData]]` internal slot is set to argument. - pub fn bigint(argument: &Value) -> Self { - let mut obj = Self { - data: ObjectData::BigInt, + pub fn bigint(value: AstBigInt) -> Self { + Self { + data: ObjectData::BigInt(value), internal_slots: FxHashMap::default(), properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, func: None, - }; - - obj.internal_slots - .insert("BigIntData".to_string(), argument.clone()); - obj + } } /// Converts the `Value` to an `Object` type. @@ -431,7 +428,7 @@ impl Object { ValueData::Rational(a) => Ok(Self::number(a)), ValueData::Integer(a) => Ok(Self::number(f64::from(a))), ValueData::String(ref a) => Ok(Self::string(a.clone())), - ValueData::BigInt(_) => Ok(Self::bigint(value)), + ValueData::BigInt(ref bigint) => Ok(Self::bigint(bigint.clone())), ValueData::Object(ref obj) => Ok((*obj).deref().borrow().clone()), _ => Err(()), } @@ -474,7 +471,7 @@ pub enum ObjectData { Error, Boolean(bool), Number(f64), - BigInt, + BigInt(AstBigInt), Ordinary, } @@ -492,7 +489,7 @@ impl Display for ObjectData { Self::Ordinary => "Ordinary", Self::Boolean(_) => "Boolean", Self::Number(_) => "Number", - Self::BigInt => "BigInt", + Self::BigInt(_) => "BigInt", } ) } diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 99016633b70..8cd1987da8f 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -364,8 +364,8 @@ impl ValueData { ValueData::BigInt(b) => Some(b.clone()), ValueData::Object(ref o) => { let object = (o).deref().borrow(); - if object.data == ObjectData::BigInt { - object.get_internal_slot("BigIntData").to_bigint() + if let ObjectData::BigInt(ref bigint) = object.data { + Some(bigint.clone()) } else { None } diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index f4780a12860..312bda57c8c 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -318,14 +318,14 @@ impl Interpreter { )) } ValueData::Object(_) | ValueData::Symbol(_) => Ok(value.clone()), - ValueData::BigInt(_) => { + ValueData::BigInt(ref bigint) => { let proto = self .realm .environment .get_binding_value("BigInt") .get_field(PROTOTYPE); - let bigint_obj = Value::new_object_from_prototype(proto, ObjectData::BigInt); - bigint_obj.set_internal_slot("BigIntData", value.clone()); + let bigint_obj = + Value::new_object_from_prototype(proto, ObjectData::BigInt(bigint.clone())); Ok(bigint_obj) } } From 1b76706ed43496b04014dc01ab38b23f25a1058f Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Tue, 26 May 2020 20:14:44 +0200 Subject: [PATCH 4/4] Attemting to specialize Function object --- boa/src/builtins/array/mod.rs | 2 +- boa/src/builtins/function/mod.rs | 15 +++++++------- boa/src/builtins/object/mod.rs | 35 ++++++++++---------------------- boa/src/builtins/value/mod.rs | 12 +++++------ boa/src/exec/expression/mod.rs | 15 +++++++------- boa/src/exec/mod.rs | 12 ++++++----- 6 files changed, 39 insertions(+), 52 deletions(-) diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 2f79c7ce4ac..76a0fa4a932 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -176,7 +176,7 @@ impl Array { // 1. ValueData::Object(ref obj) => { // 2. - if (*obj).deref().borrow().data == ObjectData::Array { + if let ObjectData::Array = (*obj).deref().borrow().data { return Ok(value_true); } Ok(value_false) diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index f77969c6df5..d678ce6e100 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -368,7 +368,10 @@ pub fn create_unmapped_arguments_object(arguments_list: &[Value]) -> Value { /// // This gets called when a new Function() is created. pub fn make_function(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue { - this.set_data(ObjectData::Function); + this.set_data(ObjectData::Function(Function::builtin( + Vec::new(), + |_, _, _| Ok(Value::undefined()), + ))); Ok(this.clone()) } @@ -399,8 +402,7 @@ pub fn make_constructor_fn( let func_prototype = global.get_field("Function").get_field(PROTOTYPE); // Create the function object and point its instance prototype to Function.prototype - let mut constructor_obj = Object::function(); - constructor_obj.set_func(constructor_fn); + let mut constructor_obj = Object::function(constructor_fn); constructor_obj.set_internal_slot(INSTANCE_PROTOTYPE, func_prototype); let constructor_val = Value::from(constructor_obj); @@ -433,12 +435,9 @@ pub fn make_builtin_fn(function: NativeFunctionData, name: N, parent: &Value, where N: Into, { - let func = Function::builtin(Vec::new(), function); + let func = Object::function(Function::builtin(Vec::new(), function)); - let mut new_func = Object::function(); - new_func.set_func(func); - - let new_func_obj = Value::from(new_func); + let new_func_obj = Value::from(func); new_func_obj.set_field("length", length); parent.set_field(name.into(), new_func_obj); diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 980882505f7..7d24d7595b7 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -55,8 +55,6 @@ pub struct Object { pub sym_properties: FxHashMap, /// Some rust object that stores internal state pub state: Option, - /// Function - pub func: Option, } impl ObjectInternalMethods for Object { @@ -325,7 +323,6 @@ impl Object { properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, - func: None, }; object.set_internal_slot("extensible", Value::from(true)); @@ -333,14 +330,13 @@ impl Object { } /// Return a new ObjectData struct, with `kind` set to Ordinary - pub fn function() -> Self { + pub fn function(function: Function) -> Self { let mut object = Self { - data: ObjectData::Function, + data: ObjectData::Function(function), internal_slots: FxHashMap::default(), properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, - func: None, }; object.set_internal_slot("extensible", Value::from(true)); @@ -363,11 +359,6 @@ impl Object { obj } - /// Set the function this object wraps - pub fn set_func(&mut self, val: Function) { - self.func = Some(val); - } - /// Return a new Boolean object whose `[[BooleanData]]` internal slot is set to argument. pub fn boolean(value: bool) -> Self { Self { @@ -376,7 +367,6 @@ impl Object { properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, - func: None, } } @@ -388,7 +378,6 @@ impl Object { properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, - func: None, } } @@ -400,7 +389,6 @@ impl Object { properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, - func: None, } } @@ -412,7 +400,6 @@ impl Object { properties: FxHashMap::default(), sym_properties: FxHashMap::default(), state: None, - func: None, } } @@ -441,9 +428,9 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-iscallable pub fn is_callable(&self) -> bool { - match self.func { - Some(ref function) => function.is_callable(), - None => false, + match self.data { + ObjectData::Function(ref function) => function.is_callable(), + _ => false, } } @@ -454,17 +441,17 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-isconstructor pub fn is_constructable(&self) -> bool { - match self.func { - Some(ref function) => function.is_constructable(), - None => false, + match self.data { + ObjectData::Function(ref function) => function.is_constructable(), + _ => false, } } } /// Defines the different types of objects. -#[derive(Debug, Trace, Finalize, Clone, PartialEq)] +#[derive(Debug, Trace, Finalize, Clone)] pub enum ObjectData { - Function, + Function(Function), Array, String(String), Symbol, @@ -481,7 +468,7 @@ impl Display for ObjectData { f, "{}", match self { - Self::Function => "Function", + Self::Function(_) => "Function", Self::Array => "Array", Self::String(_) => "String", Self::Symbol => "Symbol", diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 8cd1987da8f..c2351973acf 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -614,7 +614,7 @@ impl ValueData { let val = val.into(); if let Self::Object(ref obj) = *self { - if obj.borrow().data == ObjectData::Array { + if let ObjectData::Array = obj.borrow().data { if let Ok(num) = field.to_string().parse::() { if num > 0 { let len = i32::from(&self.get_field("length")); @@ -677,13 +677,11 @@ impl ValueData { } /// Consume the function and return a Value - pub fn from_func(native_func: Function) -> Value { - // Object with Kind set to function - let mut new_func = crate::builtins::object::Object::function(); + pub fn from_func(function: Function) -> Value { // Get Length - let length = native_func.params.len(); - // Set [[Call]] internal slot - new_func.set_func(native_func); + let length = function.params.len(); + // Object with Kind set to function + let new_func = Object::function(function); // Wrap Object in GC'd Value let new_func_val = Value::from(new_func); // Set length to parameters diff --git a/boa/src/exec/expression/mod.rs b/boa/src/exec/expression/mod.rs index 7eb72bef594..e146e96f8b3 100644 --- a/boa/src/exec/expression/mod.rs +++ b/boa/src/exec/expression/mod.rs @@ -3,7 +3,7 @@ use super::{Executable, Interpreter}; use crate::{ builtins::{ - object::{INSTANCE_PROTOTYPE, PROTOTYPE}, + object::{ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE}, value::{ResultValue, Value, ValueData}, }, syntax::ast::node::{Call, New, Node}, @@ -69,12 +69,13 @@ impl Executable for New { this.set_internal_slot(INSTANCE_PROTOTYPE, func_object.get_field(PROTOTYPE)); match func_object.data() { - ValueData::Object(ref o) => o.clone().borrow_mut().func.as_ref().unwrap().construct( - func_object.clone(), - &mut this, - &v_args, - interpreter, - ), + ValueData::Object(ref obj) => { + let obj = (**obj).borrow(); + if let ObjectData::Function(ref func) = obj.data { + return func.construct(func_object.clone(), &mut this, &v_args, interpreter); + } + panic!("TypeError: not a function"); + } _ => Ok(Value::undefined()), } } diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 312bda57c8c..4bfb139ccfc 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -97,8 +97,8 @@ impl Interpreter { callable, ); - let mut new_func = Object::function(); - new_func.set_func(func); + let new_func = Object::function(func); + let val = Value::from(new_func); val.set_internal_slot(INSTANCE_PROTOTYPE, function_prototype.clone()); val.set_field(PROTOTYPE, proto); @@ -122,8 +122,10 @@ impl Interpreter { match *f.data() { ValueData::Object(ref obj) => { let obj = (**obj).borrow(); - let func = obj.func.as_ref().expect("Expected function"); - func.call(f.clone(), this, arguments_list, self) + if let ObjectData::Function(ref func) = obj.data { + return func.call(f.clone(), this, arguments_list, self); + } + panic!("TypeError: not a function"); } _ => Err(Value::undefined()), } @@ -151,7 +153,7 @@ impl Interpreter { pub(crate) fn extract_array_properties(&mut self, value: &Value) -> Result, ()> { if let ValueData::Object(ref x) = *value.deref().borrow() { // Check if object is array - if x.deref().borrow().data == ObjectData::Array { + if let ObjectData::Array = x.deref().borrow().data { let length: i32 = self.value_to_rust_number(&value.get_field("length")) as i32; let values: Vec = (0..length) .map(|idx| value.get_field(idx.to_string()))