Skip to content

Commit

Permalink
Merge 604489f into 928d67b
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat authored Apr 8, 2023
2 parents 928d67b + 604489f commit e8a1b4a
Show file tree
Hide file tree
Showing 100 changed files with 3,555 additions and 950 deletions.
7 changes: 7 additions & 0 deletions boa_cli/src/debug/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ mod function;
mod gc;
mod object;
mod optimizer;
mod shape;

fn create_boa_object(context: &mut Context<'_>) -> JsObject {
let function_module = function::create_object(context);
let object_module = object::create_object(context);
let shape_module = shape::create_object(context);
let optimizer_module = optimizer::create_object(context);
let gc_module = gc::create_object(context);

Expand All @@ -25,6 +27,11 @@ fn create_boa_object(context: &mut Context<'_>) -> JsObject {
object_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
"shape",
shape_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
"optimizer",
optimizer_module,
Expand Down
66 changes: 66 additions & 0 deletions boa_cli/src/debug/shape.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use boa_engine::{
js_string, object::ObjectInitializer, Context, JsArgs, JsNativeError, JsObject, JsResult,
JsValue, NativeFunction,
};

fn get_object(args: &[JsValue], position: usize) -> JsResult<&JsObject> {
let value = args.get_or_undefined(position);

let Some(object) = value.as_object() else {
return Err(JsNativeError::typ()
.with_message(format!("expected object in argument position {position}, got {}", value.type_of()))
.into());
};

Ok(object)
}

/// Returns object's shape pointer in memory.
fn id(_: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult<JsValue> {
let object = get_object(args, 0)?;
let object = object.borrow();
let shape = object.shape();
Ok(format!("0x{:X}", shape.to_addr_usize()).into())
}

/// Returns object's shape type.
fn r#type(_: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult<JsValue> {
let object = get_object(args, 0)?;
let object = object.borrow();
let shape = object.shape();

Ok(if shape.is_shared() {
js_string!("shared")
} else {
js_string!("unique")
}
.into())
}

/// Returns object's shape type.
fn same(_: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult<JsValue> {
let lhs = get_object(args, 0)?;
let rhs = get_object(args, 1)?;

let lhs_shape_ptr = {
let object = lhs.borrow();
let shape = object.shape();
shape.to_addr_usize()
};

let rhs_shape_ptr = {
let object = rhs.borrow();
let shape = object.shape();
shape.to_addr_usize()
};

Ok(JsValue::new(lhs_shape_ptr == rhs_shape_ptr))
}

pub(super) fn create_object(context: &mut Context<'_>) -> JsObject {
ObjectInitializer::new(context)
.function(NativeFunction::from_fn_ptr(id), "id", 1)
.function(NativeFunction::from_fn_ptr(r#type), "type", 1)
.function(NativeFunction::from_fn_ptr(same), "same", 2)
.build()
}
6 changes: 4 additions & 2 deletions boa_engine/benches/full.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Benchmarks of the whole execution engine in Boa.
use boa_engine::{
context::DefaultHooks, optimizer::OptimizerOptions, realm::Realm, Context, Source,
context::DefaultHooks, object::shape::SharedShape, optimizer::OptimizerOptions, realm::Realm,
Context, Source,
};
use criterion::{criterion_group, criterion_main, Criterion};
use std::hint::black_box;
Expand All @@ -15,7 +16,8 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

fn create_realm(c: &mut Criterion) {
c.bench_function("Create Realm", move |b| {
b.iter(|| Realm::create(&DefaultHooks))
let root_shape = SharedShape::root();
b.iter(|| Realm::create(&DefaultHooks, &root_shape))
});
}

Expand Down
3 changes: 2 additions & 1 deletion boa_engine/src/builtins/array/array_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ impl ArrayIterator {
kind: PropertyNameKind,
context: &Context<'_>,
) -> JsValue {
let array_iterator = JsObject::from_proto_and_data(
let array_iterator = JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(),
context.intrinsics().objects().iterator_prototypes().array(),
ObjectData::array_iterator(Self::new(array, kind)),
);
Expand Down
90 changes: 59 additions & 31 deletions boa_engine/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,21 @@ impl IntrinsicObject for Array {
let symbol_iterator = JsSymbol::iterator();
let symbol_unscopables = JsSymbol::unscopables();

let get_species = BuiltInBuilder::new(intrinsics)
.callable(Self::get_species)
let get_species = BuiltInBuilder::callable(intrinsics, Self::get_species)
.name("get [Symbol.species]")
.build();

let values_function =
BuiltInBuilder::with_object(intrinsics, intrinsics.objects().array_prototype_values())
.callable(Self::values)
.name("values")
.build();
let values_function = BuiltInBuilder::callable_with_object(
intrinsics,
intrinsics.objects().array_prototype_values(),
Self::values,
)
.name("values")
.build();

let unscopables_object = Self::unscopables_object();

BuiltInBuilder::from_standard_constructor::<Self>(intrinsics)
BuiltInBuilder::from_standard_constructor_with_prototype::<Self>(intrinsics)
.static_accessor(
JsSymbol::species(),
Some(get_species),
Expand Down Expand Up @@ -203,17 +204,18 @@ impl BuiltInConstructor for Array {

// b. Let array be ? ArrayCreate(numberOfArgs, proto).
let array = Self::array_create(number_of_args as u64, Some(prototype), context)?;

// c. Let k be 0.
// d. Repeat, while k < numberOfArgs,
for (i, item) in args.iter().cloned().enumerate() {
// i. Let Pk be ! ToString(𝔽(k)).
// ii. Let itemK be values[k].
// iii. Perform ! CreateDataPropertyOrThrow(array, Pk, itemK).
array
.create_data_property_or_throw(i, item, context)
.expect("this CreateDataPropertyOrThrow must not fail");
// iv. Set k to k + 1.
}
// i. Let Pk be ! ToString(𝔽(k)).
// ii. Let itemK be values[k].
// iii. Perform ! CreateDataPropertyOrThrow(array, Pk, itemK).
// iv. Set k to k + 1.
array
.borrow_mut()
.properties_mut()
.override_indexed_properties(args.iter().cloned().collect());

// e. Assert: The mathematical value of array's "length" property is numberOfArgs.
// f. Return array.
Ok(array.into())
Expand All @@ -239,14 +241,43 @@ impl Array {
.with_message("array exceeded max size")
.into());
}

// Fast path:
if prototype.is_none() {
return Ok(context
.intrinsics()
.templates()
.array()
.create(ObjectData::array(), vec![JsValue::new(length)]));
}

// 7. Return A.
// 2. If proto is not present, set proto to %Array.prototype%.
// 3. Let A be ! MakeBasicObject(« [[Prototype]], [[Extensible]] »).
// 4. Set A.[[Prototype]] to proto.
// 5. Set A.[[DefineOwnProperty]] as specified in 10.4.2.1.
let prototype =
prototype.unwrap_or_else(|| context.intrinsics().constructors().array().prototype());
let array = JsObject::from_proto_and_data(prototype, ObjectData::array());

// Fast path:
if context
.intrinsics()
.templates()
.array()
.has_prototype(&prototype)
{
return Ok(context
.intrinsics()
.templates()
.array()
.create(ObjectData::array(), vec![JsValue::new(length)]));
}

let array = JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(),
prototype,
ObjectData::array(),
);

// 6. Perform ! OrdinaryDefineOwnProperty(A, "length", PropertyDescriptor { [[Value]]: 𝔽(length), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
crate::object::internal_methods::ordinary_define_own_property(
Expand Down Expand Up @@ -276,27 +307,24 @@ impl Array {
{
// 1. Assert: elements is a List whose elements are all ECMAScript language values.
// 2. Let array be ! ArrayCreate(0).
let array = Self::array_create(0, None, context)
.expect("creating an empty array with the default prototype must not fail");

// 3. Let n be 0.
// 4. For each element e of elements, do
// a. Perform ! CreateDataPropertyOrThrow(array, ! ToString(𝔽(n)), e).
// b. Set n to n + 1.
//
// 5. Return array.
// NOTE: This deviates from the spec, but it should have the same behaviour.
let elements: ThinVec<_> = elements.into_iter().collect();
let length = elements.len();
array
.borrow_mut()
.properties_mut()
.override_indexed_properties(elements);
array
.set(utf16!("length"), length, true, context)
.expect("Should not fail");

// 5. Return array.
array
context
.intrinsics()
.templates()
.array()
.create_with_indexed_properties(
ObjectData::array(),
vec![JsValue::new(length)],
elements,
)
}

/// Utility function for concatenating array objects.
Expand Down
11 changes: 5 additions & 6 deletions boa_engine/src/builtins/array_buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,15 @@ impl IntrinsicObject for ArrayBuffer {

let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE;

let get_species = BuiltInBuilder::new(intrinsics)
.callable(Self::get_species)
let get_species = BuiltInBuilder::callable(intrinsics, Self::get_species)
.name("get [Symbol.species]")
.build();

let get_byte_length = BuiltInBuilder::new(intrinsics)
.callable(Self::get_byte_length)
let get_byte_length = BuiltInBuilder::callable(intrinsics, Self::get_byte_length)
.name("get byteLength")
.build();

BuiltInBuilder::from_standard_constructor::<Self>(intrinsics)
BuiltInBuilder::from_standard_constructor_with_prototype::<Self>(intrinsics)
.accessor(
utf16!("byteLength"),
Some(get_byte_length),
Expand Down Expand Up @@ -354,7 +352,8 @@ impl ArrayBuffer {

// 3. Set obj.[[ArrayBufferData]] to block.
// 4. Set obj.[[ArrayBufferByteLength]] to byteLength.
let obj = JsObject::from_proto_and_data(
let obj = JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(),
prototype,
ObjectData::array_buffer(Self {
array_buffer_data: Some(block),
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/async_function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl IntrinsicObject for AsyncFunction {
fn init(intrinsics: &Intrinsics) {
let _timer = Profiler::global().start_event(Self::NAME, "init");

BuiltInBuilder::from_standard_constructor::<Self>(intrinsics)
BuiltInBuilder::from_standard_constructor_with_prototype::<Self>(intrinsics)
.prototype(intrinsics.constructors().function().constructor())
.inherits(Some(intrinsics.constructors().function().prototype()))
.property(
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/async_generator_function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl IntrinsicObject for AsyncGeneratorFunction {
fn init(intrinsics: &Intrinsics) {
let _timer = Profiler::global().start_event(Self::NAME, "init");

BuiltInBuilder::from_standard_constructor::<Self>(intrinsics)
BuiltInBuilder::from_standard_constructor_with_prototype::<Self>(intrinsics)
.inherits(Some(intrinsics.constructors().function().prototype()))
.constructor_attributes(Attribute::CONFIGURABLE)
.property(
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/bigint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl IntrinsicObject for BigInt {
fn init(intrinsics: &Intrinsics) {
let _timer = Profiler::global().start_event(Self::NAME, "init");

BuiltInBuilder::from_standard_constructor::<Self>(intrinsics)
BuiltInBuilder::from_standard_constructor_with_prototype::<Self>(intrinsics)
.method(Self::to_string, "toString", 0)
.method(Self::value_of, "valueOf", 0)
.static_method(Self::as_int_n, "asIntN", 2)
Expand Down
8 changes: 6 additions & 2 deletions boa_engine/src/builtins/boolean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl IntrinsicObject for Boolean {
fn init(intrinsics: &Intrinsics) {
let _timer = Profiler::global().start_event(Self::NAME, "init");

BuiltInBuilder::from_standard_constructor::<Self>(intrinsics)
BuiltInBuilder::from_standard_constructor_with_prototype::<Self>(intrinsics)
.method(Self::to_string, "toString", 0)
.method(Self::value_of, "valueOf", 0)
.build();
Expand Down Expand Up @@ -67,7 +67,11 @@ impl BuiltInConstructor for Boolean {
}
let prototype =
get_prototype_from_constructor(new_target, StandardConstructors::boolean, context)?;
let boolean = JsObject::from_proto_and_data(prototype, ObjectData::boolean(data));
let boolean = JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(),
prototype,
ObjectData::boolean(data),
);

Ok(boolean.into())
}
Expand Down
14 changes: 6 additions & 8 deletions boa_engine/src/builtins/dataview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,19 @@ impl IntrinsicObject for DataView {
fn init(intrinsics: &Intrinsics) {
let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE;

let get_buffer = BuiltInBuilder::new(intrinsics)
.callable(Self::get_buffer)
let get_buffer = BuiltInBuilder::callable(intrinsics, Self::get_buffer)
.name("get buffer")
.build();

let get_byte_length = BuiltInBuilder::new(intrinsics)
.callable(Self::get_byte_length)
let get_byte_length = BuiltInBuilder::callable(intrinsics, Self::get_byte_length)
.name("get byteLength")
.build();

let get_byte_offset = BuiltInBuilder::new(intrinsics)
.callable(Self::get_byte_offset)
let get_byte_offset = BuiltInBuilder::callable(intrinsics, Self::get_byte_offset)
.name("get byteOffset")
.build();

BuiltInBuilder::from_standard_constructor::<Self>(intrinsics)
BuiltInBuilder::from_standard_constructor_with_prototype::<Self>(intrinsics)
.accessor(utf16!("buffer"), Some(get_buffer), None, flag_attributes)
.accessor(
utf16!("byteLength"),
Expand Down Expand Up @@ -193,7 +190,8 @@ impl BuiltInConstructor for DataView {
.into());
}

let obj = JsObject::from_proto_and_data(
let obj = JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(),
prototype,
ObjectData::data_view(Self {
// 11. Set O.[[ViewedArrayBuffer]] to buffer.
Expand Down
Loading

0 comments on commit e8a1b4a

Please sign in to comment.