Browse Source

Implement static shapes

optimization/static-shapes
Haled Odat 2 years ago
parent
commit
85b2861b3e
  1. 22
      Cargo.lock
  2. 2
      Cargo.toml
  3. 25
      boa_builtins/Cargo.toml
  4. 1
      boa_builtins/README.md
  5. 1485
      boa_builtins/build.rs
  6. 181
      boa_builtins/src/lib.rs
  7. 6
      boa_cli/src/debug/shape.rs
  8. 3
      boa_engine/Cargo.toml
  9. 118
      boa_engine/src/builtins/array/mod.rs
  10. 37
      boa_engine/src/builtins/array_buffer/mod.rs
  11. 24
      boa_engine/src/builtins/bigint/mod.rs
  12. 12
      boa_engine/src/builtins/boolean/mod.rs
  13. 75
      boa_engine/src/builtins/dataview/mod.rs
  14. 122
      boa_engine/src/builtins/date/mod.rs
  15. 21
      boa_engine/src/builtins/error/aggregate.rs
  16. 20
      boa_engine/src/builtins/error/eval.rs
  17. 16
      boa_engine/src/builtins/error/mod.rs
  18. 20
      boa_engine/src/builtins/error/range.rs
  19. 20
      boa_engine/src/builtins/error/reference.rs
  20. 20
      boa_engine/src/builtins/error/syntax.rs
  21. 19
      boa_engine/src/builtins/error/type.rs
  22. 20
      boa_engine/src/builtins/error/uri.rs
  23. 4
      boa_engine/src/builtins/escape/mod.rs
  24. 2
      boa_engine/src/builtins/eval/mod.rs
  25. 93
      boa_engine/src/builtins/function/mod.rs
  26. 19
      boa_engine/src/builtins/json/mod.rs
  27. 59
      boa_engine/src/builtins/map/mod.rs
  28. 109
      boa_engine/src/builtins/math/mod.rs
  29. 371
      boa_engine/src/builtins/mod.rs
  30. 8
      boa_engine/src/builtins/number/globals.rs
  31. 68
      boa_engine/src/builtins/number/mod.rs
  32. 91
      boa_engine/src/builtins/object/mod.rs
  33. 43
      boa_engine/src/builtins/promise/mod.rs
  34. 47
      boa_engine/src/builtins/reflect/mod.rs
  35. 75
      boa_engine/src/builtins/regexp/mod.rs
  36. 61
      boa_engine/src/builtins/set/mod.rs
  37. 133
      boa_engine/src/builtins/string/mod.rs
  38. 77
      boa_engine/src/builtins/symbol/mod.rs
  39. 164
      boa_engine/src/builtins/typed_array/mod.rs
  40. 16
      boa_engine/src/builtins/uri/mod.rs
  41. 18
      boa_engine/src/builtins/weak/weak_ref.rs
  42. 23
      boa_engine/src/builtins/weak_map/mod.rs
  43. 21
      boa_engine/src/builtins/weak_set/mod.rs
  44. 130
      boa_engine/src/context/intrinsics.rs
  45. 13
      boa_engine/src/object/builtins/jsfunction.rs
  46. 25
      boa_engine/src/object/jsobject.rs
  47. 29
      boa_engine/src/object/mod.rs
  48. 38
      boa_engine/src/object/property_map.rs
  49. 36
      boa_engine/src/object/shape/mod.rs
  50. 2
      boa_engine/src/object/shape/slot.rs
  51. 149
      boa_engine/src/object/shape/static_shape.rs
  52. 465
      boa_engine/src/string/common.rs
  53. 22
      boa_engine/src/string/mod.rs
  54. 2
      boa_engine/src/symbol.rs
  55. 8
      boa_engine/src/vm/opcode/set/property.rs

22
Cargo.lock generated

@ -377,6 +377,17 @@ dependencies = [
"serde",
]
[[package]]
name = "boa_builtins"
version = "0.16.0"
dependencies = [
"bitflags 2.3.1",
"boa_macros",
"phf",
"phf_codegen",
"phf_shared",
]
[[package]]
name = "boa_cli"
version = "0.16.0"
@ -403,6 +414,7 @@ version = "0.16.0"
dependencies = [
"bitflags 2.3.1",
"boa_ast",
"boa_builtins",
"boa_gc",
"boa_icu_provider",
"boa_interner",
@ -3018,6 +3030,16 @@ dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.1"

2
Cargo.toml

@ -1,6 +1,7 @@
[workspace]
members = [
"boa_ast",
"boa_builtins",
"boa_cli",
"boa_engine",
"boa_examples",
@ -28,6 +29,7 @@ description = "Boa is a Javascript lexer, parser and compiler written in Rust. C
[workspace.dependencies]
boa_ast = { version = "0.16.0", path = "boa_ast" }
boa_builtins = { version = "0.16.0", path = "boa_builtins" }
boa_engine = { version = "0.16.0", path = "boa_engine" }
boa_gc = { version = "0.16.0", path = "boa_gc" }
boa_icu_provider = { version = "0.16.0", path = "boa_icu_provider" }

25
boa_builtins/Cargo.toml

@ -0,0 +1,25 @@
[package]
name = "boa_builtins"
description = "Builtins of the Boa JavaScript engine."
publish = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
build = "build.rs"
[features]
annex-b = []
[dependencies]
bitflags = "2.1.0"
phf = "^0.11.1"
phf_shared = "^0.11.1"
[build-dependencies]
boa_macros.workspace = true
phf_codegen = "^0.11.1"
phf_shared = "^0.11.1"
bitflags = "2.1.0"

1
boa_builtins/README.md

@ -0,0 +1 @@
# TOOD

1485
boa_builtins/build.rs

File diff suppressed because it is too large Load Diff

181
boa_builtins/src/lib.rs

@ -0,0 +1,181 @@
use std::{
fmt::{self, Debug},
hash::{Hash, Hasher},
};
use bitflags::bitflags;
use phf::PhfHash;
use phf_shared::PhfBorrow;
bitflags! {
/// This struct constains the property flags as described in the ECMAScript specification.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Attribute: u8 {
/// The `Writable` attribute decides whether the value associated with the property can be changed or not, from its initial value.
const WRITABLE = 0b0000_0001;
/// If the property can be enumerated by a `for-in` loop.
const ENUMERABLE = 0b0000_0010;
/// If the property descriptor can be changed later.
const CONFIGURABLE = 0b0000_0100;
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct StaticString {
index: u16,
}
impl StaticString {
#[inline]
pub fn index(self) -> u16 {
self.index
}
}
#[derive(Clone, Copy)]
pub struct EncodedStaticPropertyKey(u16);
impl EncodedStaticPropertyKey {
#[inline]
pub fn decode(&self) -> StaticPropertyKey {
let value = self.0 >> 1;
if self.0 & 1 == 0 {
StaticPropertyKey::String(value)
} else {
StaticPropertyKey::Symbol(value as u8)
}
}
}
const fn string(index: u16) -> EncodedStaticPropertyKey {
debug_assert!(index < 2u16.pow(15));
EncodedStaticPropertyKey(index << 1)
}
const fn symbol(index: u8) -> EncodedStaticPropertyKey {
EncodedStaticPropertyKey(((index as u16) << 1) | 1)
}
impl Debug for EncodedStaticPropertyKey {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.decode().fmt(f)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum StaticPropertyKey {
String(u16),
Symbol(u8),
}
impl StaticPropertyKey {
#[inline]
pub fn encode(self) -> EncodedStaticPropertyKey {
match self {
StaticPropertyKey::String(x) => string(x),
StaticPropertyKey::Symbol(x) => symbol(x),
}
}
}
impl Debug for StaticPropertyKey {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
StaticPropertyKey::String(index) => {
let string = RAW_STATICS[index as usize];
let string = String::from_utf16_lossy(string);
write!(f, "String(\"{string}\")")
}
StaticPropertyKey::Symbol(symbol) => {
write!(f, "Symbol({symbol})")
}
}
}
}
impl Eq for EncodedStaticPropertyKey {}
impl PartialEq for EncodedStaticPropertyKey {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Hash for EncodedStaticPropertyKey {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl PhfHash for EncodedStaticPropertyKey {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
self.hash(state)
}
}
impl PhfBorrow<EncodedStaticPropertyKey> for EncodedStaticPropertyKey {
#[inline]
fn borrow(&self) -> &EncodedStaticPropertyKey {
self
}
}
pub type Slot = (u8, Attribute);
#[derive(Debug)]
pub struct StaticShape {
pub property_table: phf::OrderedMap<EncodedStaticPropertyKey, Slot>,
pub storage_len: usize,
/// \[\[Prototype\]\]
pub prototype: Option<&'static StaticShape>,
}
impl StaticShape {
#[inline]
pub fn get(&self, key: StaticPropertyKey) -> Option<Slot> {
// SAFETY: only used to extend the lifetime, so we are able to call get.
self.property_table
.get(&key.encode())
.map(|(index, attributes)| (*index, *attributes))
}
#[inline]
pub fn is_empty(&self) -> bool {
self.property_table.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.property_table.len()
}
#[inline]
pub fn get_string_key_expect(&self, index: usize) -> StaticString {
match self
.property_table
.index(index)
.expect("there should be a key at the given index")
.0
.decode()
{
StaticPropertyKey::String(index) => StaticString { index },
StaticPropertyKey::Symbol(s) => {
panic!("The key should be a string at position {index}, but symbol {s}")
}
}
}
}
include!(concat!(env!("OUT_DIR"), "/static_shapes_codegen.rs"));
// static NUMBER_BUITIN_OBJECT_STATIC_SHAPE_REF: &StaticShape = &NUMBER_BUITIN_OBJECT_STATIC_SHAPE;

6
boa_cli/src/debug/shape.rs

@ -31,8 +31,12 @@ fn r#type(_: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult<JsValu
Ok(if shape.is_shared() {
js_string!("shared")
} else {
} else if shape.is_unique() {
js_string!("unique")
} else if shape.is_static() {
js_string!("static")
} else {
unreachable!("shapes can only be shared, unique, or static")
}
.into())
}

3
boa_engine/Cargo.toml

@ -43,10 +43,11 @@ flowgraph = []
trace = []
# Enable Boa's additional ECMAScript features for web browsers.
annex-b = ["boa_parser/annex-b"]
annex-b = ["boa_parser/annex-b", "boa_builtins/annex-b"]
[dependencies]
boa_interner.workspace = true
boa_builtins.workspace = true
boa_gc = { workspace = true, features = [ "thinvec" ] }
boa_profiler.workspace = true
boa_macros.workspace = true

118
boa_engine/src/builtins/array/mod.rs

@ -21,7 +21,7 @@ use crate::{
error::JsNativeError,
js_string,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData, CONSTRUCTOR},
property::{Attribute, PropertyDescriptor, PropertyNameKind},
property::{PropertyDescriptor, PropertyNameKind},
realm::Realm,
symbol::JsSymbol,
value::{IntegerOrInfinity, JsValue},
@ -44,9 +44,6 @@ impl IntrinsicObject for Array {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let symbol_iterator = JsSymbol::iterator();
let symbol_unscopables = JsSymbol::unscopables();
let get_species = BuiltInBuilder::callable(realm, Self::get_species)
.name("get [Symbol.species]")
.build();
@ -61,71 +58,54 @@ impl IntrinsicObject for Array {
let unscopables_object = Self::unscopables_object();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.static_accessor(
JsSymbol::species(),
Some(get_species),
None,
Attribute::CONFIGURABLE,
)
.property(
utf16!("length"),
0,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
)
.property(
utf16!("values"),
values_function.clone(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
symbol_iterator,
values_function,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
symbol_unscopables,
unscopables_object,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.method(Self::at, "at", 1)
.method(Self::concat, "concat", 1)
.method(Self::push, "push", 1)
.method(Self::index_of, "indexOf", 1)
.method(Self::last_index_of, "lastIndexOf", 1)
.method(Self::includes_value, "includes", 1)
.method(Self::map, "map", 1)
.method(Self::fill, "fill", 1)
.method(Self::for_each, "forEach", 1)
.method(Self::filter, "filter", 1)
.method(Self::pop, "pop", 0)
.method(Self::join, "join", 1)
.method(Self::to_string, "toString", 0)
.method(Self::reverse, "reverse", 0)
.method(Self::shift, "shift", 0)
.method(Self::unshift, "unshift", 1)
.method(Self::every, "every", 1)
.method(Self::find, "find", 1)
.method(Self::find_index, "findIndex", 1)
.method(Self::find_last, "findLast", 1)
.method(Self::find_last_index, "findLastIndex", 1)
.method(Self::flat, "flat", 0)
.method(Self::flat_map, "flatMap", 1)
.method(Self::slice, "slice", 2)
.method(Self::some, "some", 1)
.method(Self::sort, "sort", 1)
.method(Self::splice, "splice", 2)
.method(Self::to_locale_string, "toLocaleString", 0)
.method(Self::reduce, "reduce", 1)
.method(Self::reduce_right, "reduceRight", 1)
.method(Self::keys, "keys", 0)
.method(Self::entries, "entries", 0)
.method(Self::copy_within, "copyWithin", 2)
// Static Methods
.static_method(Self::from, "from", 1)
.static_method(Self::is_array, "isArray", 1)
.static_method(Self::of, "of", 0)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::ARRAY_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::ARRAY_PROTOTYPE_STATIC_SHAPE,
)
.property(0)
.property(values_function.clone())
.property(values_function)
.property(unscopables_object)
.method(Self::at, 1)
.method(Self::concat, 1)
.method(Self::push, 1)
.method(Self::index_of, 1)
.method(Self::last_index_of, 1)
.method(Self::includes_value, 1)
.method(Self::map, 1)
.method(Self::fill, 1)
.method(Self::for_each, 1)
.method(Self::filter, 1)
.method(Self::pop, 0)
.method(Self::join, 1)
.method(Self::to_string, 0)
.method(Self::reverse, 0)
.method(Self::shift, 0)
.method(Self::unshift, 1)
.method(Self::every, 1)
.method(Self::find, 1)
.method(Self::find_index, 1)
.method(Self::find_last, 1)
.method(Self::find_last_index, 1)
.method(Self::flat, 0)
.method(Self::flat_map, 1)
.method(Self::slice, 2)
.method(Self::some, 1)
.method(Self::sort, 1)
.method(Self::splice, 2)
.method(Self::to_locale_string, 0)
.method(Self::reduce, 1)
.method(Self::reduce_right, 1)
.method(Self::keys, 0)
.method(Self::entries, 0)
.method(Self::copy_within, 2)
// Static Methods
.static_accessor(Some(get_species), None)
.static_method(Self::from, 1)
.static_method(Self::is_array, 1)
.static_method(Self::of, 0)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

37
boa_engine/src/builtins/array_buffer/mod.rs

@ -15,10 +15,7 @@ use crate::{
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
error::JsNativeError,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
symbol::JsSymbol,
value::{IntegerOrInfinity, Numeric},
Context, JsArgs, JsResult, JsValue,
};
@ -51,8 +48,6 @@ impl IntrinsicObject for ArrayBuffer {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE;
let get_species = BuiltInBuilder::callable(realm, Self::get_species)
.name("get [Symbol.species]")
.build();
@ -61,27 +56,17 @@ impl IntrinsicObject for ArrayBuffer {
.name("get byteLength")
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.accessor(
utf16!("byteLength"),
Some(get_byte_length),
None,
flag_attributes,
)
.static_accessor(
JsSymbol::species(),
Some(get_species),
None,
Attribute::CONFIGURABLE,
)
.static_method(Self::is_view, "isView", 1)
.method(Self::slice, "slice", 2)
.property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::ARRAY_BUFFER_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::ARRAY_BUFFER_PROTOTYPE_STATIC_SHAPE,
)
.static_accessor(Some(get_species), None)
.static_method(Self::is_view, 1)
.accessor(Some(get_byte_length), None)
.method(Self::slice, 2)
.property(Self::NAME)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

24
boa_engine/src/builtins/bigint/mod.rs

@ -17,9 +17,7 @@ use crate::{
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
error::JsNativeError,
object::JsObject,
property::Attribute,
realm::Realm,
symbol::JsSymbol,
value::{IntegerOrInfinity, PreferredType},
Context, JsArgs, JsBigInt, JsResult, JsValue,
};
@ -39,17 +37,17 @@ impl IntrinsicObject for BigInt {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.method(Self::to_string, "toString", 0)
.method(Self::value_of, "valueOf", 0)
.static_method(Self::as_int_n, "asIntN", 2)
.static_method(Self::as_uint_n, "asUintN", 2)
.property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::BIGINT_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::BIGINT_PROTOTYPE_STATIC_SHAPE,
)
.method(Self::to_string, 0)
.method(Self::value_of, 0)
.static_method(Self::as_int_n, 2)
.static_method(Self::as_uint_n, 2)
.property(Self::NAME)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

12
boa_engine/src/builtins/boolean/mod.rs

@ -32,10 +32,14 @@ impl IntrinsicObject for Boolean {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.method(Self::to_string, "toString", 0)
.method(Self::value_of, "valueOf", 0)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::BOOLEAN_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::BOOLEAN_PROTOTYPE_STATIC_SHAPE,
)
.method(Self::to_string, 0)
.method(Self::value_of, 0)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

75
boa_engine/src/builtins/dataview/mod.rs

@ -12,10 +12,7 @@ use crate::{
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
error::JsNativeError,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
symbol::JsSymbol,
value::JsValue,
Context, JsArgs, JsResult,
};
@ -33,8 +30,6 @@ pub struct DataView {
impl IntrinsicObject for DataView {
fn init(realm: &Realm) {
let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE;
let get_buffer = BuiltInBuilder::callable(realm, Self::get_buffer)
.name("get buffer")
.build();
@ -47,46 +42,36 @@ impl IntrinsicObject for DataView {
.name("get byteOffset")
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.accessor(utf16!("buffer"), Some(get_buffer), None, flag_attributes)
.accessor(
utf16!("byteLength"),
Some(get_byte_length),
None,
flag_attributes,
)
.accessor(
utf16!("byteOffset"),
Some(get_byte_offset),
None,
flag_attributes,
)
.method(Self::get_big_int64, "getBigInt64", 1)
.method(Self::get_big_uint64, "getBigUint64", 1)
.method(Self::get_float32, "getFloat32", 1)
.method(Self::get_float64, "getFloat64", 1)
.method(Self::get_int8, "getInt8", 1)
.method(Self::get_int16, "getInt16", 1)
.method(Self::get_int32, "getInt32", 1)
.method(Self::get_uint8, "getUint8", 1)
.method(Self::get_uint16, "getUint16", 1)
.method(Self::get_uint32, "getUint32", 1)
.method(Self::set_big_int64, "setBigInt64", 2)
.method(Self::set_big_uint64, "setBigUint64", 2)
.method(Self::set_float32, "setFloat32", 2)
.method(Self::set_float64, "setFloat64", 2)
.method(Self::set_int8, "setInt8", 2)
.method(Self::set_int16, "setInt16", 2)
.method(Self::set_int32, "setInt32", 2)
.method(Self::set_uint8, "setUint8", 2)
.method(Self::set_uint16, "setUint16", 2)
.method(Self::set_uint32, "setUint32", 2)
.property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::DATA_VIEW_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::DATA_VIEW_PROTOTYPE_STATIC_SHAPE,
)
.accessor(Some(get_buffer), None)
.accessor(Some(get_byte_length), None)
.accessor(Some(get_byte_offset), None)
.method(Self::get_big_int64, 1)
.method(Self::get_big_uint64, 1)
.method(Self::get_float32, 1)
.method(Self::get_float64, 1)
.method(Self::get_int8, 1)
.method(Self::get_int16, 1)
.method(Self::get_int32, 1)
.method(Self::get_uint8, 1)
.method(Self::get_uint16, 1)
.method(Self::get_uint32, 1)
.method(Self::set_big_int64, 2)
.method(Self::set_big_uint64, 2)
.method(Self::set_float32, 2)
.method(Self::set_float64, 2)
.method(Self::set_int8, 2)
.method(Self::set_int16, 2)
.method(Self::set_int32, 2)
.method(Self::set_uint8, 2)
.method(Self::set_uint16, 2)
.method(Self::set_uint32, 2)
.property(Self::NAME)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

122
boa_engine/src/builtins/date/mod.rs

@ -22,10 +22,8 @@ use crate::{
error::JsNativeError,
js_string,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
symbol::JsSymbol,
value::{IntegerOrNan, JsValue, PreferredType},
Context, JsArgs, JsError, JsResult,
};
@ -106,70 +104,62 @@ impl IntrinsicObject for Date {
.length(1)
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.static_method(Self::now, "now", 0)
.static_method(Self::parse, "parse", 1)
.static_method(Self::utc, "UTC", 7)
.method(Self::get_date::<true>, "getDate", 0)
.method(Self::get_day::<true>, "getDay", 0)
.method(Self::get_full_year::<true>, "getFullYear", 0)
.method(Self::get_hours::<true>, "getHours", 0)
.method(Self::get_milliseconds::<true>, "getMilliseconds", 0)
.method(Self::get_minutes::<true>, "getMinutes", 0)
.method(Self::get_month::<true>, "getMonth", 0)
.method(Self::get_seconds::<true>, "getSeconds", 0)
.method(Self::get_time, "getTime", 0)
.method(Self::get_timezone_offset, "getTimezoneOffset", 0)
.method(Self::get_date::<false>, "getUTCDate", 0)
.method(Self::get_day::<false>, "getUTCDay", 0)
.method(Self::get_full_year::<false>, "getUTCFullYear", 0)
.method(Self::get_hours::<false>, "getUTCHours", 0)
.method(Self::get_milliseconds::<false>, "getUTCMilliseconds", 0)
.method(Self::get_minutes::<false>, "getUTCMinutes", 0)
.method(Self::get_month::<false>, "getUTCMonth", 0)
.method(Self::get_seconds::<false>, "getUTCSeconds", 0)
.method(Self::get_year, "getYear", 0)
.method(Self::set_date::<true>, "setDate", 1)
.method(Self::set_full_year::<true>, "setFullYear", 3)
.method(Self::set_hours::<true>, "setHours", 4)
.method(Self::set_milliseconds::<true>, "setMilliseconds", 1)
.method(Self::set_minutes::<true>, "setMinutes", 3)
.method(Self::set_month::<true>, "setMonth", 2)
.method(Self::set_seconds::<true>, "setSeconds", 2)
.method(Self::set_time, "setTime", 1)
.method(Self::set_date::<false>, "setUTCDate", 1)
.method(Self::set_full_year::<false>, "setUTCFullYear", 3)
.method(Self::set_hours::<false>, "setUTCHours", 4)
.method(Self::set_milliseconds::<false>, "setUTCMilliseconds", 1)
.method(Self::set_minutes::<false>, "setUTCMinutes", 3)
.method(Self::set_month::<false>, "setUTCMonth", 2)
.method(Self::set_seconds::<false>, "setUTCSeconds", 2)
.method(Self::set_year, "setYear", 1)
.method(Self::to_date_string, "toDateString", 0)
.method(Self::to_iso_string, "toISOString", 0)
.method(Self::to_json, "toJSON", 1)
.method(Self::to_locale_date_string, "toLocaleDateString", 0)
.method(Self::to_locale_string, "toLocaleString", 0)
.method(Self::to_locale_time_string, "toLocaleTimeString", 0)
.method(Self::to_string, "toString", 0)
.method(Self::to_time_string, "toTimeString", 0)
.method(Self::value_of, "valueOf", 0)
.property(
"toGMTString",
to_utc_string.clone(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
"toUTCString",
to_utc_string,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
JsSymbol::to_primitive(),
to_primitive,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::DATE_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::DATE_PROTOTYPE_STATIC_SHAPE,
)
.static_method(Self::now, 0)
.static_method(Self::parse, 1)
.static_method(Self::utc, 7)
.method(Self::get_date::<true>, 0)
.method(Self::get_day::<true>, 0)
.method(Self::get_full_year::<true>, 0)
.method(Self::get_hours::<true>, 0)
.method(Self::get_milliseconds::<true>, 0)
.method(Self::get_minutes::<true>, 0)
.method(Self::get_month::<true>, 0)
.method(Self::get_seconds::<true>, 0)
.method(Self::get_time, 0)
.method(Self::get_timezone_offset, 0)
.method(Self::get_date::<false>, 0)
.method(Self::get_day::<false>, 0)
.method(Self::get_full_year::<false>, 0)
.method(Self::get_hours::<false>, 0)
.method(Self::get_milliseconds::<false>, 0)
.method(Self::get_minutes::<false>, 0)
.method(Self::get_month::<false>, 0)
.method(Self::get_seconds::<false>, 0)
.method(Self::get_year, 0)
.method(Self::set_date::<true>, 1)
.method(Self::set_full_year::<true>, 3)
.method(Self::set_hours::<true>, 4)
.method(Self::set_milliseconds::<true>, 1)
.method(Self::set_minutes::<true>, 3)
.method(Self::set_month::<true>, 2)
.method(Self::set_seconds::<true>, 2)
.method(Self::set_time, 1)
.method(Self::set_date::<false>, 1)
.method(Self::set_full_year::<false>, 3)
.method(Self::set_hours::<false>, 4)
.method(Self::set_milliseconds::<false>, 1)
.method(Self::set_minutes::<false>, 3)
.method(Self::set_month::<false>, 2)
.method(Self::set_seconds::<false>, 2)
.method(Self::set_year, 1)
.method(Self::to_date_string, 0)
.method(Self::to_iso_string, 0)
.method(Self::to_json, 1)
.method(Self::to_locale_date_string, 0)
.method(Self::to_locale_string, 0)
.method(Self::to_locale_time_string, 0)
.method(Self::to_string, 0)
.method(Self::to_time_string, 0)
.method(Self::value_of, 0)
.property(to_utc_string.clone())
.property(to_utc_string)
.property(to_primitive)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

21
boa_engine/src/builtins/error/aggregate.rs

@ -14,10 +14,10 @@ use crate::{
},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::{Attribute, PropertyDescriptorBuilder},
property::PropertyDescriptorBuilder,
realm::Realm,
string::utf16,
Context, JsArgs, JsResult, JsValue,
Context, JsArgs, JsResult, JsString, JsValue,
};
use boa_profiler::Profiler;
@ -30,13 +30,16 @@ impl IntrinsicObject for AggregateError {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(utf16!("name"), Self::NAME, attribute)
.property(utf16!("message"), "", attribute)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::NATIVE_ERROR_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::NATIVE_ERROR_PROTOTYPE_STATIC_SHAPE,
)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(Self::NAME)
.property(JsString::default())
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

20
boa_engine/src/builtins/error/eval.rs

@ -15,10 +15,9 @@ use crate::{
builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
Context, JsArgs, JsResult, JsValue,
Context, JsArgs, JsResult, JsString, JsValue,
};
use boa_profiler::Profiler;
@ -32,13 +31,16 @@ impl IntrinsicObject for EvalError {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(utf16!("name"), Self::NAME, attribute)
.property(utf16!("message"), "", attribute)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::NATIVE_ERROR_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::NATIVE_ERROR_PROTOTYPE_STATIC_SHAPE,
)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(Self::NAME)
.property(JsString::default())
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

16
boa_engine/src/builtins/error/mod.rs

@ -16,7 +16,6 @@ use crate::{
error::JsNativeError,
js_string,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
Context, JsArgs, JsResult, JsValue,
@ -131,12 +130,15 @@ impl IntrinsicObject for Error {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.property(utf16!("name"), Self::NAME, attribute)
.property(utf16!("message"), "", attribute)
.method(Self::to_string, "toString", 0)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::ERROR_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::ERROR_PROTOTYPE_STATIC_SHAPE,
)
.property(Self::NAME)
.property(js_string!(""))
.method(Self::to_string, 0)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

20
boa_engine/src/builtins/error/range.rs

@ -13,10 +13,9 @@ use crate::{
builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
Context, JsArgs, JsResult, JsValue,
Context, JsArgs, JsResult, JsString, JsValue,
};
use boa_profiler::Profiler;
@ -30,13 +29,16 @@ impl IntrinsicObject for RangeError {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(utf16!("name"), Self::NAME, attribute)
.property(utf16!("message"), "", attribute)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::NATIVE_ERROR_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::NATIVE_ERROR_PROTOTYPE_STATIC_SHAPE,
)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(Self::NAME)
.property(JsString::default())
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

20
boa_engine/src/builtins/error/reference.rs

@ -13,10 +13,9 @@ use crate::{
builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
Context, JsArgs, JsResult, JsValue,
Context, JsArgs, JsResult, JsString, JsValue,
};
use boa_profiler::Profiler;
@ -29,13 +28,16 @@ impl IntrinsicObject for ReferenceError {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(utf16!("name"), Self::NAME, attribute)
.property(utf16!("message"), "", attribute)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::NATIVE_ERROR_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::NATIVE_ERROR_PROTOTYPE_STATIC_SHAPE,
)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(Self::NAME)
.property(JsString::default())
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

20
boa_engine/src/builtins/error/syntax.rs

@ -15,10 +15,9 @@ use crate::{
builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
Context, JsArgs, JsResult, JsValue,
Context, JsArgs, JsResult, JsString, JsValue,
};
use boa_profiler::Profiler;
@ -32,13 +31,16 @@ impl IntrinsicObject for SyntaxError {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(utf16!("name"), Self::NAME, attribute)
.property(utf16!("message"), "", attribute)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::NATIVE_ERROR_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::NATIVE_ERROR_PROTOTYPE_STATIC_SHAPE,
)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(Self::NAME)
.property(JsString::default())
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

19
boa_engine/src/builtins/error/type.rs

@ -26,7 +26,7 @@ use crate::{
property::Attribute,
realm::Realm,
string::utf16,
Context, JsArgs, JsResult, JsValue, NativeFunction,
Context, JsArgs, JsResult, JsString, JsValue, NativeFunction,
};
use boa_profiler::Profiler;
@ -40,13 +40,16 @@ impl IntrinsicObject for TypeError {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(utf16!("name"), Self::NAME, attribute)
.property(utf16!("message"), "", attribute)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::NATIVE_ERROR_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::NATIVE_ERROR_PROTOTYPE_STATIC_SHAPE,
)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(Self::NAME)
.property(JsString::default())
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

20
boa_engine/src/builtins/error/uri.rs

@ -14,10 +14,9 @@ use crate::{
builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
Context, JsArgs, JsResult, JsValue,
Context, JsArgs, JsResult, JsString, JsValue,
};
use boa_profiler::Profiler;
@ -31,13 +30,16 @@ impl IntrinsicObject for UriError {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(utf16!("name"), Self::NAME, attribute)
.property(utf16!("message"), "", attribute)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::NATIVE_ERROR_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::NATIVE_ERROR_PROTOTYPE_STATIC_SHAPE,
)
.prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(Self::NAME)
.property(JsString::default())
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

4
boa_engine/src/builtins/escape/mod.rs

@ -23,7 +23,7 @@ pub(crate) struct Escape;
impl IntrinsicObject for Escape {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, escape)
BuiltInBuilder::callable_intrinsic::<Self>(realm, escape)
.name(Self::NAME)
.length(1)
.build();
@ -95,7 +95,7 @@ pub(crate) struct Unescape;
impl IntrinsicObject for Unescape {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, unescape)
BuiltInBuilder::callable_intrinsic::<Self>(realm, unescape)
.name(Self::NAME)
.length(1)
.build();

2
boa_engine/src/builtins/eval/mod.rs

@ -35,7 +35,7 @@ impl IntrinsicObject for Eval {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, Self::eval)
BuiltInBuilder::callable_intrinsic::<Self>(realm, Self::eval)
.name(Self::NAME)
.length(1)
.build();

93
boa_engine/src/builtins/function/mod.rs

@ -19,12 +19,14 @@ use crate::{
error::JsNativeError,
js_string,
native_function::NativeFunction,
object::{internal_methods::get_prototype_from_constructor, JsObject, Object, ObjectData},
object::{JsFunction, PrivateElement, PrivateName},
property::{Attribute, PropertyDescriptor, PropertyKey},
object::{
internal_methods::get_prototype_from_constructor, JsObject, Object, ObjectData, ObjectKind,
PrivateName,
},
object::{JsFunction, PrivateElement},
property::{PropertyDescriptor, PropertyKey},
realm::Realm,
string::utf16,
symbol::JsSymbol,
value::IntegerOrInfinity,
vm::{ActiveRunnable, CodeBlock},
Context, JsArgs, JsResult, JsString, JsValue,
@ -468,33 +470,65 @@ impl IntrinsicObject for BuiltInFunctionObject {
let throw_type_error = realm.intrinsics().objects().throw_type_error();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.method(Self::apply, "apply", 2)
.method(Self::bind, "bind", 1)
.method(Self::call, "call", 1)
.method(Self::to_string, "toString", 0)
.property(JsSymbol::has_instance(), has_instance, Attribute::default())
.accessor(
utf16!("caller"),
Some(throw_type_error.clone()),
Some(throw_type_error.clone()),
Attribute::CONFIGURABLE,
)
.accessor(
utf16!("arguments"),
Some(throw_type_error.clone()),
Some(throw_type_error),
Attribute::CONFIGURABLE,
)
.build();
// BuiltInBuilder::from_standard_constructor::<Self>(realm)
// .method(Self::apply, "apply", 2)
// .method(Self::bind, "bind", 1)
// .method(Self::call, "call", 1)
// .method(Self::to_string, "toString", 0)
// .property(JsSymbol::has_instance(), has_instance, Attribute::default())
// .accessor(
// utf16!("caller"),
// Some(throw_type_error.clone()),
// Some(throw_type_error.clone()),
// Attribute::CONFIGURABLE,
// )
// .accessor(
// utf16!("arguments"),
// Some(throw_type_error.clone()),
// Some(throw_type_error),
// Attribute::CONFIGURABLE,
// )
// .build();
// BuiltInBuilder::callable_with_object(realm, prototype.clone(), Self::prototype)
// .name("")
// .length(0)
// .build();
// prototype.set_prototype(Some(realm.intrinsics().constructors().object().prototype()));
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::FUNCTION_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::FUNCTION_PROTOTYPE_STATIC_SHAPE,
)
.property(0)
.property("")
.method(Self::apply, 2)
.method(Self::bind, 1)
.method(Self::call, 1)
.method(Self::to_string, 0)
.property(has_instance)
.accessor(
Some(throw_type_error.clone()),
Some(throw_type_error.clone()),
)
.accessor(Some(throw_type_error.clone()), Some(throw_type_error))
.build();
let prototype = realm.intrinsics().constructors().function().prototype();
BuiltInBuilder::callable_with_object(realm, prototype.clone(), Self::prototype)
.name("")
.length(0)
.build();
{
let mut prototype = prototype.borrow_mut();
let function = Function::new(
FunctionKind::Native {
function: NativeFunction::from_fn_ptr(Self::prototype),
constructor: (true).then_some(ConstructorKind::Base),
},
realm.clone(),
);
*prototype.kind_mut() = ObjectKind::Function(function);
}
// TODO: improve this, because it's converting the static shape into a unique one, on initialization.
prototype.set_prototype(Some(realm.intrinsics().constructors().object().prototype()));
}
@ -1013,6 +1047,7 @@ impl BuiltInFunctionObject {
Ok(JsValue::ordinary_has_instance(this, args.get_or_undefined(0), context)?.into())
}
#[allow(dead_code)]
#[allow(clippy::unnecessary_wraps)]
fn prototype(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult<JsValue> {
Ok(JsValue::undefined())

19
boa_engine/src/builtins/json/mod.rs

@ -24,10 +24,9 @@ use crate::{
error::JsNativeError,
js_string,
object::JsObject,
property::{Attribute, PropertyNameKind},
property::PropertyNameKind,
realm::Realm,
string::{utf16, CodePoint},
symbol::JsSymbol,
value::IntegerOrInfinity,
vm::CallFrame,
Context, JsArgs, JsResult, JsString, JsValue,
@ -50,14 +49,14 @@ impl IntrinsicObject for Json {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let to_string_tag = JsSymbol::to_string_tag();
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::with_intrinsic::<Self>(realm)
.static_method(Self::parse, "parse", 2)
.static_method(Self::stringify, "stringify", 3)
.static_property(to_string_tag, Self::NAME, attribute)
.build();
BuiltInBuilder::with_intrinsic_static_shape::<Self>(
realm,
&boa_builtins::JSON_OBJECT_STATIC_SHAPE,
)
.static_method(Self::parse, 2)
.static_method(Self::stringify, 3)
.static_property(Self::NAME)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

59
boa_engine/src/builtins/map/mod.rs

@ -15,10 +15,9 @@ use crate::{
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
error::JsNativeError,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::{Attribute, PropertyNameKind},
property::PropertyNameKind,
realm::Realm,
string::utf16,
symbol::JsSymbol,
Context, JsArgs, JsResult, JsValue,
};
use boa_profiler::Profiler;
@ -53,43 +52,25 @@ impl IntrinsicObject for Map {
.name("entries")
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.static_accessor(
JsSymbol::species(),
Some(get_species),
None,
Attribute::CONFIGURABLE,
)
.property(
utf16!("entries"),
entries_function.clone(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
JsSymbol::iterator(),
entries_function,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.method(Self::clear, "clear", 0)
.method(Self::delete, "delete", 1)
.method(Self::for_each, "forEach", 1)
.method(Self::get, "get", 1)
.method(Self::has, "has", 1)
.method(Self::keys, "keys", 0)
.method(Self::set, "set", 2)
.method(Self::values, "values", 0)
.accessor(
utf16!("size"),
Some(get_size),
None,
Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::MAP_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::MAP_PROTOTYPE_STATIC_SHAPE,
)
.static_accessor(Some(get_species), None)
.property(entries_function.clone())
.property(entries_function)
.property(Self::NAME)
.method(Self::clear, 0)
.method(Self::delete, 1)
.method(Self::for_each, 1)
.method(Self::get, 1)
.method(Self::has, 1)
.method(Self::keys, 0)
.method(Self::set, 2)
.method(Self::values, 0)
.accessor(Some(get_size), None)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

109
boa_engine/src/builtins/math/mod.rs

@ -12,9 +12,8 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math
use crate::{
builtins::BuiltInObject, context::intrinsics::Intrinsics, object::JsObject,
property::Attribute, realm::Realm, string::utf16, symbol::JsSymbol, Context, JsArgs, JsResult,
JsValue,
builtins::BuiltInObject, context::intrinsics::Intrinsics, object::JsObject, realm::Realm,
Context, JsArgs, JsResult, JsValue,
};
use boa_profiler::Profiler;
@ -31,61 +30,55 @@ impl IntrinsicObject for Math {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
BuiltInBuilder::with_intrinsic::<Self>(realm)
.static_property(utf16!("E"), std::f64::consts::E, attribute)
.static_property(utf16!("LN10"), std::f64::consts::LN_10, attribute)
.static_property(utf16!("LN2"), std::f64::consts::LN_2, attribute)
.static_property(utf16!("LOG10E"), std::f64::consts::LOG10_E, attribute)
.static_property(utf16!("LOG2E"), std::f64::consts::LOG2_E, attribute)
.static_property(utf16!("PI"), std::f64::consts::PI, attribute)
.static_property(
utf16!("SQRT1_2"),
std::f64::consts::FRAC_1_SQRT_2,
attribute,
)
.static_property(utf16!("SQRT2"), std::f64::consts::SQRT_2, attribute)
.static_method(Self::abs, "abs", 1)
.static_method(Self::acos, "acos", 1)
.static_method(Self::acosh, "acosh", 1)
.static_method(Self::asin, "asin", 1)
.static_method(Self::asinh, "asinh", 1)
.static_method(Self::atan, "atan", 1)
.static_method(Self::atanh, "atanh", 1)
.static_method(Self::atan2, "atan2", 2)
.static_method(Self::cbrt, "cbrt", 1)
.static_method(Self::ceil, "ceil", 1)
.static_method(Self::clz32, "clz32", 1)
.static_method(Self::cos, "cos", 1)
.static_method(Self::cosh, "cosh", 1)
.static_method(Self::exp, "exp", 1)
.static_method(Self::expm1, "expm1", 1)
.static_method(Self::floor, "floor", 1)
.static_method(Self::fround, "fround", 1)
.static_method(Self::hypot, "hypot", 2)
.static_method(Self::imul, "imul", 2)
.static_method(Self::log, "log", 1)
.static_method(Self::log1p, "log1p", 1)
.static_method(Self::log10, "log10", 1)
.static_method(Self::log2, "log2", 1)
.static_method(Self::max, "max", 2)
.static_method(Self::min, "min", 2)
.static_method(Self::pow, "pow", 2)
.static_method(Self::random, "random", 0)
.static_method(Self::round, "round", 1)
.static_method(Self::sign, "sign", 1)
.static_method(Self::sin, "sin", 1)
.static_method(Self::sinh, "sinh", 1)
.static_method(Self::sqrt, "sqrt", 1)
.static_method(Self::tan, "tan", 1)
.static_method(Self::tanh, "tanh", 1)
.static_method(Self::trunc, "trunc", 1)
.static_property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::with_intrinsic_static_shape::<Self>(
realm,
&boa_builtins::MATH_OBJECT_STATIC_SHAPE,
)
.static_property(std::f64::consts::E)
.static_property(std::f64::consts::LN_10)
.static_property(std::f64::consts::LN_2)
.static_property(std::f64::consts::LOG10_E)
.static_property(std::f64::consts::LOG2_E)
.static_property(std::f64::consts::PI)
.static_property(std::f64::consts::FRAC_1_SQRT_2)
.static_property(std::f64::consts::SQRT_2)
.static_method(Self::abs, 1)
.static_method(Self::acos, 1)
.static_method(Self::acosh, 1)
.static_method(Self::asin, 1)
.static_method(Self::asinh, 1)
.static_method(Self::atan, 1)
.static_method(Self::atanh, 1)
.static_method(Self::atan2, 2)
.static_method(Self::cbrt, 1)
.static_method(Self::ceil, 1)
.static_method(Self::clz32, 1)
.static_method(Self::cos, 1)
.static_method(Self::cosh, 1)
.static_method(Self::exp, 1)
.static_method(Self::expm1, 1)
.static_method(Self::floor, 1)
.static_method(Self::fround, 1)
.static_method(Self::hypot, 2)
.static_method(Self::imul, 2)
.static_method(Self::log, 1)
.static_method(Self::log1p, 1)
.static_method(Self::log10, 1)
.static_method(Self::log2, 1)
.static_method(Self::max, 2)
.static_method(Self::min, 2)
.static_method(Self::pow, 2)
.static_method(Self::random, 0)
.static_method(Self::round, 1)
.static_method(Self::sign, 1)
.static_method(Self::sin, 1)
.static_method(Self::sinh, 1)
.static_method(Self::sqrt, 1)
.static_method(Self::tan, 1)
.static_method(Self::tanh, 1)
.static_method(Self::trunc, 1)
.static_property(Self::NAME)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

371
boa_engine/src/builtins/mod.rs

@ -39,6 +39,8 @@ pub mod escape;
#[cfg(feature = "intl")]
pub mod intl;
use boa_builtins::StaticShape as RawStaticShape;
pub(crate) use self::{
array::Array,
async_function::AsyncFunction,
@ -95,7 +97,9 @@ use crate::{
js_string,
native_function::{NativeFunction, NativeFunctionPointer},
object::{
shape::{property_table::PropertyTableInner, slot::SlotAttributes},
shape::{
property_table::PropertyTableInner, slot::SlotAttributes, static_shape::StaticShape,
},
FunctionBinding, JsFunction, JsObject, JsPrototype, Object, ObjectData, ObjectKind,
CONSTRUCTOR, PROTOTYPE,
},
@ -587,19 +591,318 @@ struct BuiltInBuilder<'ctx, Kind> {
prototype: JsObject,
}
impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> {
// fn new(realm: &'ctx Realm) -> BuiltInBuilder<'ctx, OrdinaryObject> {
// BuiltInBuilder {
// realm,
// object: BuiltInObjectInitializer::Unique {
// object: Object::default(),
// data: ObjectData::ordinary(),
// },
// kind: OrdinaryObject,
// prototype: realm.intrinsics().constructors().object().prototype(),
// }
// }
struct BuiltInBuilderCallableIntrinsic<'ctx> {
realm: &'ctx Realm,
function: NativeFunctionPointer,
object: JsObject,
name: JsString,
length: usize,
}
impl BuiltInBuilderCallableIntrinsic<'_> {
fn name<N: Into<JsString>>(mut self, name: N) -> Self {
self.name = name.into();
self
}
/// Specify how many arguments the constructor function takes.
///
/// Default is `0`.
const fn length(mut self, length: usize) -> Self {
self.length = length;
self
}
fn build(self) {
let function = function::Function::new(
function::FunctionKind::Native {
function: NativeFunction::from_fn_ptr(self.function),
constructor: (true).then_some(function::ConstructorKind::Base),
},
self.realm.clone(),
);
let mut object = self.object.borrow_mut();
object.properties_mut().shape = self
.realm
.intrinsics()
.templates()
.function()
.shape()
.clone()
.into();
object.properties_mut().storage = vec![self.length.into(), self.name.into()];
*object.kind_mut() = ObjectKind::Function(function);
}
}
struct BuiltInBuilderConstructorStaticShape<'ctx> {
realm: &'ctx Realm,
function: NativeFunctionPointer,
constructor_property_index: usize,
constructor_object: JsObject,
constructor_shape: &'static RawStaticShape,
constructor_storage: Vec<JsValue>,
prototype_property_index: usize,
prototype_object: JsObject,
prototype_shape: &'static RawStaticShape,
prototype_storage: Vec<JsValue>,
__proto__: JsPrototype,
inherits: Option<JsObject>,
}
impl<'ctx> BuiltInBuilder<'ctx, Callable<Constructor>> {
fn from_standard_constructor_static_shape<SC: BuiltInConstructor>(
realm: &'ctx Realm,
constructor_shape: &'static RawStaticShape,
prototype_shape: &'static RawStaticShape,
) -> BuiltInBuilderConstructorStaticShape<'ctx> {
let constructor = SC::STANDARD_CONSTRUCTOR(realm.intrinsics().constructors());
// println!("{constructor_shape:#?}");
// println!("{prototype_shape:#?}");
let mut this = BuiltInBuilderConstructorStaticShape {
realm,
function: SC::constructor,
constructor_property_index: 0,
constructor_shape,
constructor_storage: Vec::with_capacity(constructor_shape.storage_len),
constructor_object: constructor.constructor(),
prototype_property_index: 0,
prototype_shape,
prototype_storage: Vec::with_capacity(prototype_shape.storage_len),
prototype_object: constructor.prototype(),
__proto__: Some(realm.intrinsics().constructors().function().prototype()),
inherits: Some(realm.intrinsics().constructors().object().prototype()),
};
this.constructor_storage.push(SC::LENGTH.into());
this.constructor_storage.push(js_string!(SC::NAME).into());
this.constructor_storage
.push(this.prototype_object.clone().into());
this.constructor_property_index += 3;
this.prototype_storage
.push(this.constructor_object.clone().into());
this.prototype_property_index += 1;
this
}
}
#[allow(dead_code)]
impl BuiltInBuilderConstructorStaticShape<'_> {
/// Adds a new static method to the builtin object.
fn static_method(mut self, function: NativeFunctionPointer, length: usize) -> Self {
let name = self
.constructor_shape
.get_string_key_expect(self.constructor_property_index);
let function = BuiltInBuilder::callable(self.realm, function)
.name(name)
.length(length)
.build();
self.constructor_storage.push(function.into());
self.constructor_property_index += 1;
self
}
/// Adds a new static data property to the builtin object.
fn static_property<V>(mut self, value: V) -> Self
where
V: Into<JsValue>,
{
self.constructor_storage.push(value.into());
self.constructor_property_index += 1;
self
}
/// Specify the `[[Prototype]]` internal field of the builtin object.
///
/// Default is `Function.prototype` for constructors and `Object.prototype` for statics.
fn prototype(mut self, prototype: JsObject) -> Self {
self.__proto__ = Some(prototype);
self
}
/// Adds a new method to the constructor's prototype.
fn method(mut self, function: NativeFunctionPointer, length: usize) -> Self {
let name = self
.prototype_shape
.get_string_key_expect(self.prototype_property_index);
let function = BuiltInBuilder::callable(self.realm, function)
.name(name)
.length(length)
.build();
self.prototype_storage.push(function.into());
self.prototype_property_index += 1;
self
}
fn method_with_name(
mut self,
function: NativeFunctionPointer,
name: JsString,
length: usize,
) -> Self {
let function = BuiltInBuilder::callable(self.realm, function)
.name(name)
.length(length)
.build();
self.prototype_storage.push(function.into());
self.prototype_property_index += 1;
self
}
/// Adds a new data property to the constructor's prototype.
fn property<V>(mut self, value: V) -> Self
where
V: Into<JsValue>,
{
self.prototype_storage.push(value.into());
self.prototype_property_index += 1;
self
}
/// Adds new accessor property to the constructor's prototype.
fn accessor(mut self, get: Option<JsFunction>, set: Option<JsFunction>) -> Self {
self.prototype_storage.extend([
get.map(JsValue::new).unwrap_or_default(),
set.map(JsValue::new).unwrap_or_default(),
]);
self.prototype_property_index += 1;
self
}
fn static_accessor(mut self, get: Option<JsFunction>, set: Option<JsFunction>) -> Self {
self.constructor_storage.extend([
get.map(JsValue::new).unwrap_or_default(),
set.map(JsValue::new).unwrap_or_default(),
]);
self.constructor_property_index += 1;
self
}
/// Specifies the parent prototype which objects created by this constructor inherit from.
///
/// Default is `Object.prototype`.
#[allow(clippy::missing_const_for_fn)]
fn inherits(mut self, prototype: JsPrototype) -> Self {
self.inherits = prototype;
self
}
fn build(mut self) {
debug_assert_eq!(
self.constructor_storage.len() + 1,
self.constructor_shape.storage_len
);
debug_assert_eq!(
self.constructor_storage.capacity(),
self.constructor_shape.storage_len
);
let function = function::Function::new(
function::FunctionKind::Native {
function: NativeFunction::from_fn_ptr(self.function),
constructor: (true).then_some(function::ConstructorKind::Base),
},
self.realm.clone(),
);
let mut object = self.constructor_object.borrow_mut();
*object.kind_mut() = ObjectKind::Function(function);
object.properties_mut().shape = StaticShape::new(self.constructor_shape).into();
self.constructor_storage.push(
self.__proto__
.unwrap_or_else(|| {
self.realm
.intrinsics()
.constructors()
.function()
.prototype()
})
.into(),
);
object.properties_mut().storage = self.constructor_storage;
debug_assert_eq!(
self.prototype_storage.len() + 1,
self.prototype_shape.storage_len
);
debug_assert_eq!(
self.prototype_storage.capacity(),
self.prototype_shape.storage_len
);
let mut prototype = self.prototype_object.borrow_mut();
prototype.properties_mut().shape = StaticShape::new(self.prototype_shape).into();
self.prototype_storage
.push(self.inherits.map(JsValue::new).unwrap_or_default());
prototype.properties_mut().storage = self.prototype_storage;
}
}
struct BuiltInBuilderStaticShape<'ctx> {
realm: &'ctx Realm,
shape: &'static RawStaticShape,
object: JsObject,
property_index: usize,
storage: Vec<JsValue>,
}
impl BuiltInBuilderStaticShape<'_> {
/// Adds a new static method to the builtin object.
fn static_method(mut self, function: NativeFunctionPointer, length: usize) -> Self {
let name = self.shape.get_string_key_expect(self.property_index);
let function = BuiltInBuilder::callable(self.realm, function)
.name(name)
.length(length)
.build();
self.storage.push(function.into());
self.property_index += 1;
self
}
/// Adds a new static data property to the builtin object.
fn static_property<V>(mut self, value: V) -> Self
where
V: Into<JsValue>,
{
self.storage.push(value.into());
self.property_index += 1;
self
}
fn build(mut self) {
debug_assert_eq!(self.storage.len(), self.shape.len());
debug_assert_eq!(self.storage.len() + 1, self.shape.storage_len);
debug_assert_eq!(self.storage.capacity(), self.shape.storage_len);
let mut object = self.object.borrow_mut();
object.properties_mut().shape = StaticShape::new(self.shape).into();
self.storage.push(
self.realm
.intrinsics()
.constructors()
.object()
.prototype()
.into(),
);
object.properties_mut().storage = self.storage;
}
}
impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> {
fn with_intrinsic<I: IntrinsicObject>(
realm: &'ctx Realm,
) -> BuiltInBuilder<'ctx, OrdinaryObject> {
@ -610,6 +913,19 @@ impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> {
prototype: realm.intrinsics().constructors().object().prototype(),
}
}
fn with_intrinsic_static_shape<I: IntrinsicObject>(
realm: &'ctx Realm,
shape: &'static boa_builtins::StaticShape,
) -> BuiltInBuilderStaticShape<'ctx> {
BuiltInBuilderStaticShape {
realm,
shape,
object: I::get(realm.intrinsics()),
storage: Vec::with_capacity(shape.storage_len),
property_index: 0,
}
}
}
struct BuiltInConstructorWithPrototype<'ctx> {
@ -625,6 +941,7 @@ struct BuiltInConstructorWithPrototype<'ctx> {
prototype_property_table: PropertyTableInner,
prototype_storage: Vec<JsValue>,
prototype: JsObject,
__proto__: JsPrototype,
inherits: Option<JsObject>,
attributes: Attribute,
@ -943,21 +1260,16 @@ impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> {
}
}
fn callable_with_intrinsic<I: IntrinsicObject>(
fn callable_intrinsic<I: IntrinsicObject>(
realm: &'ctx Realm,
function: NativeFunctionPointer,
) -> BuiltInBuilder<'ctx, Callable<OrdinaryFunction>> {
BuiltInBuilder {
) -> BuiltInBuilderCallableIntrinsic<'ctx> {
BuiltInBuilderCallableIntrinsic {
realm,
object: BuiltInObjectInitializer::Shared(I::get(realm.intrinsics())),
kind: Callable {
function,
name: js_string!(""),
length: 0,
kind: OrdinaryFunction,
realm: realm.clone(),
},
prototype: realm.intrinsics().constructors().function().prototype(),
function,
object: I::get(realm.intrinsics()),
name: JsString::default(),
length: 0,
}
}
@ -1057,15 +1369,6 @@ impl<T> BuiltInBuilder<'_, T> {
}
impl<FnTyp> BuiltInBuilder<'_, Callable<FnTyp>> {
/// Specify how many arguments the constructor function takes.
///
/// Default is `0`.
#[inline]
const fn length(mut self, length: usize) -> Self {
self.kind.length = length;
self
}
/// Specify the name of the constructor function.
///
/// Default is `""`

8
boa_engine/src/builtins/number/globals.rs

@ -38,7 +38,7 @@ pub(crate) struct IsFinite;
impl IntrinsicObject for IsFinite {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, is_finite)
BuiltInBuilder::callable_intrinsic::<Self>(realm, is_finite)
.name(Self::NAME)
.length(1)
.build();
@ -84,7 +84,7 @@ pub(crate) struct IsNaN;
impl IntrinsicObject for IsNaN {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, is_nan)
BuiltInBuilder::callable_intrinsic::<Self>(realm, is_nan)
.name(Self::NAME)
.length(1)
.build();
@ -225,7 +225,7 @@ pub(crate) struct ParseInt;
impl IntrinsicObject for ParseInt {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, parse_int)
BuiltInBuilder::callable_intrinsic::<Self>(realm, parse_int)
.name(Self::NAME)
.length(2)
.build();
@ -298,7 +298,7 @@ pub(crate) struct ParseFloat;
impl IntrinsicObject for ParseFloat {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, parse_float)
BuiltInBuilder::callable_intrinsic::<Self>(realm, parse_float)
.name(Self::NAME)
.length(1)
.build();

68
boa_engine/src/builtins/number/mod.rs

@ -18,9 +18,7 @@ use crate::{
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
error::JsNativeError,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
string::utf16,
value::{AbstractRelation, IntegerOrInfinity, JsValue},
Context, JsArgs, JsResult,
};
@ -49,46 +47,32 @@ impl IntrinsicObject for Number {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.static_property(utf16!("EPSILON"), f64::EPSILON, attribute)
.static_property(
utf16!("MAX_SAFE_INTEGER"),
Self::MAX_SAFE_INTEGER,
attribute,
)
.static_property(
utf16!("MIN_SAFE_INTEGER"),
Self::MIN_SAFE_INTEGER,
attribute,
)
.static_property(utf16!("MAX_VALUE"), Self::MAX_VALUE, attribute)
.static_property(utf16!("MIN_VALUE"), Self::MIN_VALUE, attribute)
.static_property(utf16!("NEGATIVE_INFINITY"), f64::NEG_INFINITY, attribute)
.static_property(utf16!("POSITIVE_INFINITY"), f64::INFINITY, attribute)
.static_property(utf16!("NaN"), f64::NAN, attribute)
.static_property(
utf16!("parseInt"),
realm.intrinsics().objects().parse_int(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
utf16!("parseFloat"),
realm.intrinsics().objects().parse_float(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_method(Self::number_is_finite, "isFinite", 1)
.static_method(Self::number_is_nan, "isNaN", 1)
.static_method(Self::is_safe_integer, "isSafeInteger", 1)
.static_method(Self::number_is_integer, "isInteger", 1)
.method(Self::to_exponential, "toExponential", 1)
.method(Self::to_fixed, "toFixed", 1)
.method(Self::to_locale_string, "toLocaleString", 0)
.method(Self::to_precision, "toPrecision", 1)
.method(Self::to_string, "toString", 1)
.method(Self::value_of, "valueOf", 0)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::NUMBER_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::NUMBER_PROTOTYPE_STATIC_SHAPE,
)
.static_property(f64::EPSILON)
.static_property(Self::MAX_SAFE_INTEGER)
.static_property(Self::MIN_SAFE_INTEGER)
.static_property(Self::MAX_VALUE)
.static_property(Self::MIN_VALUE)
.static_property(f64::NEG_INFINITY)
.static_property(f64::INFINITY)
.static_property(f64::NAN)
.static_property(realm.intrinsics().objects().parse_int())
.static_property(realm.intrinsics().objects().parse_float())
.static_method(Self::number_is_finite, 1)
.static_method(Self::number_is_nan, 1)
.static_method(Self::is_safe_integer, 1)
.static_method(Self::number_is_integer, 1)
.method(Self::to_exponential, 1)
.method(Self::to_fixed, 1)
.method(Self::to_locale_string, 0)
.method(Self::to_precision, 1)
.method(Self::to_string, 1)
.method(Self::value_of, 0)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

91
boa_engine/src/builtins/object/mod.rs

@ -26,7 +26,7 @@ use crate::{
internal_methods::get_prototype_from_constructor, FunctionObjectBuilder, IntegrityLevel,
JsObject, ObjectData, ObjectKind,
},
property::{Attribute, PropertyDescriptor, PropertyKey, PropertyNameKind},
property::{PropertyDescriptor, PropertyKey, PropertyNameKind},
realm::Realm,
string::utf16,
symbol::JsSymbol,
@ -56,55 +56,46 @@ impl IntrinsicObject for Object {
.name("set __proto__")
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.inherits(None)
.accessor(
utf16!("__proto__"),
Some(legacy_proto_getter),
Some(legacy_setter_proto),
Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.method(Self::has_own_property, "hasOwnProperty", 1)
.method(Self::property_is_enumerable, "propertyIsEnumerable", 1)
.method(Self::to_string, "toString", 0)
.method(Self::to_locale_string, "toLocaleString", 0)
.method(Self::value_of, "valueOf", 0)
.method(Self::is_prototype_of, "isPrototypeOf", 1)
.method(Self::legacy_define_getter, "__defineGetter__", 2)
.method(Self::legacy_define_setter, "__defineSetter__", 2)
.method(Self::legacy_lookup_getter, "__lookupGetter__", 1)
.method(Self::legacy_lookup_setter, "__lookupSetter__", 1)
.static_method(Self::create, "create", 2)
.static_method(Self::set_prototype_of, "setPrototypeOf", 2)
.static_method(Self::get_prototype_of, "getPrototypeOf", 1)
.static_method(Self::define_property, "defineProperty", 3)
.static_method(Self::define_properties, "defineProperties", 2)
.static_method(Self::assign, "assign", 2)
.static_method(Self::is, "is", 2)
.static_method(Self::keys, "keys", 1)
.static_method(Self::values, "values", 1)
.static_method(Self::entries, "entries", 1)
.static_method(Self::seal, "seal", 1)
.static_method(Self::is_sealed, "isSealed", 1)
.static_method(Self::freeze, "freeze", 1)
.static_method(Self::is_frozen, "isFrozen", 1)
.static_method(Self::prevent_extensions, "preventExtensions", 1)
.static_method(Self::is_extensible, "isExtensible", 1)
.static_method(
Self::get_own_property_descriptor,
"getOwnPropertyDescriptor",
2,
)
.static_method(
Self::get_own_property_descriptors,
"getOwnPropertyDescriptors",
1,
)
.static_method(Self::get_own_property_names, "getOwnPropertyNames", 1)
.static_method(Self::get_own_property_symbols, "getOwnPropertySymbols", 1)
.static_method(Self::has_own, "hasOwn", 2)
.static_method(Self::from_entries, "fromEntries", 1)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::OBJECT_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::OBJECT_PROTOTYPE_STATIC_SHAPE,
)
.inherits(None)
.accessor(Some(legacy_proto_getter), Some(legacy_setter_proto))
.method(Self::has_own_property, 1)
.method(Self::property_is_enumerable, 1)
.method(Self::to_string, 0)
.method(Self::to_locale_string, 0)
.method(Self::value_of, 0)
.method(Self::is_prototype_of, 1)
.method(Self::legacy_define_getter, 2)
.method(Self::legacy_define_setter, 2)
.method(Self::legacy_lookup_getter, 1)
.method(Self::legacy_lookup_setter, 1)
.static_method(Self::create, 2)
.static_method(Self::set_prototype_of, 2)
.static_method(Self::get_prototype_of, 1)
.static_method(Self::define_property, 3)
.static_method(Self::define_properties, 2)
.static_method(Self::assign, 2)
.static_method(Self::is, 2)
.static_method(Self::keys, 1)
.static_method(Self::values, 1)
.static_method(Self::entries, 1)
.static_method(Self::seal, 1)
.static_method(Self::is_sealed, 1)
.static_method(Self::freeze, 1)
.static_method(Self::is_frozen, 1)
.static_method(Self::prevent_extensions, 1)
.static_method(Self::is_extensible, 1)
.static_method(Self::get_own_property_descriptor, 2)
.static_method(Self::get_own_property_descriptors, 1)
.static_method(Self::get_own_property_names, 1)
.static_method(Self::get_own_property_symbols, 1)
.static_method(Self::has_own, 2)
.static_method(Self::from_entries, 1)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

43
boa_engine/src/builtins/promise/mod.rs

@ -14,10 +14,8 @@ use crate::{
internal_methods::get_prototype_from_constructor, FunctionObjectBuilder, JsFunction,
JsObject, ObjectData, CONSTRUCTOR,
},
property::Attribute,
realm::Realm,
string::utf16,
symbol::JsSymbol,
value::JsValue,
Context, JsArgs, JsError, JsResult,
};
@ -324,29 +322,24 @@ impl IntrinsicObject for Promise {
.name("get [Symbol.species]")
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.static_method(Self::all, "all", 1)
.static_method(Self::all_settled, "allSettled", 1)
.static_method(Self::any, "any", 1)
.static_method(Self::race, "race", 1)
.static_method(Self::reject, "reject", 1)
.static_method(Self::resolve, "resolve", 1)
.static_accessor(
JsSymbol::species(),
Some(get_species),
None,
Attribute::CONFIGURABLE,
)
.method(Self::then, "then", 2)
.method(Self::catch, "catch", 1)
.method(Self::finally, "finally", 1)
// <https://tc39.es/ecma262/#sec-promise.prototype-@@tostringtag>
.property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::PROMISE_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::PROMISE_PROTOTYPE_STATIC_SHAPE,
)
.static_method(Self::all, 1)
.static_method(Self::all_settled, 1)
.static_method(Self::any, 1)
.static_method(Self::race, 1)
.static_method(Self::reject, 1)
.static_method(Self::resolve, 1)
.static_accessor(Some(get_species), None)
.method(Self::then, 2)
.method(Self::catch, 1)
.method(Self::finally, 1)
// <https://tc39.es/ecma262/#sec-promise.prototype-@@tostringtag>
.property(Self::NAME)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

47
boa_engine/src/builtins/reflect/mod.rs

@ -16,9 +16,7 @@ use crate::{
context::intrinsics::Intrinsics,
error::JsNativeError,
object::JsObject,
property::Attribute,
realm::Realm,
symbol::JsSymbol,
Context, JsArgs, JsResult, JsValue,
};
use boa_profiler::Profiler;
@ -34,32 +32,25 @@ impl IntrinsicObject for Reflect {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let to_string_tag = JsSymbol::to_string_tag();
BuiltInBuilder::with_intrinsic::<Self>(realm)
.static_method(Self::apply, "apply", 3)
.static_method(Self::construct, "construct", 2)
.static_method(Self::define_property, "defineProperty", 3)
.static_method(Self::delete_property, "deleteProperty", 2)
.static_method(Self::get, "get", 2)
.static_method(
Self::get_own_property_descriptor,
"getOwnPropertyDescriptor",
2,
)
.static_method(Self::get_prototype_of, "getPrototypeOf", 1)
.static_method(Self::has, "has", 2)
.static_method(Self::is_extensible, "isExtensible", 1)
.static_method(Self::own_keys, "ownKeys", 1)
.static_method(Self::prevent_extensions, "preventExtensions", 1)
.static_method(Self::set, "set", 3)
.static_method(Self::set_prototype_of, "setPrototypeOf", 2)
.static_property(
to_string_tag,
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::with_intrinsic_static_shape::<Self>(
realm,
&boa_builtins::REFLECT_OBJECT_STATIC_SHAPE,
)
.static_method(Self::apply, 3)
.static_method(Self::construct, 2)
.static_method(Self::define_property, 3)
.static_method(Self::delete_property, 2)
.static_method(Self::get, 2)
.static_method(Self::get_own_property_descriptor, 2)
.static_method(Self::get_prototype_of, 1)
.static_method(Self::has, 2)
.static_method(Self::is_extensible, 1)
.static_method(Self::own_keys, 1)
.static_method(Self::prevent_extensions, 1)
.static_method(Self::set, 3)
.static_method(Self::set_prototype_of, 2)
.static_property(Self::NAME)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

75
boa_engine/src/builtins/regexp/mod.rs

@ -18,7 +18,7 @@ use crate::{
internal_methods::get_prototype_from_constructor, JsObject, ObjectData, ObjectKind,
CONSTRUCTOR,
},
property::{Attribute, PropertyDescriptorBuilder},
property::PropertyDescriptorBuilder,
realm::Realm,
string::{utf16, CodePoint},
symbol::JsSymbol,
@ -55,8 +55,6 @@ impl IntrinsicObject for RegExp {
.name("get [Symbol.species]")
.build();
let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE;
let get_has_indices = BuiltInBuilder::callable(realm, Self::get_has_indices)
.name("get hasIndices")
.build();
@ -84,53 +82,34 @@ impl IntrinsicObject for RegExp {
let get_source = BuiltInBuilder::callable(realm, Self::get_source)
.name("get source")
.build();
let regexp = BuiltInBuilder::from_standard_constructor::<Self>(realm)
.static_accessor(
JsSymbol::species(),
Some(get_species),
None,
Attribute::CONFIGURABLE,
)
.property(utf16!("lastIndex"), 0, Attribute::all())
.method(Self::test, "test", 1)
.method(Self::exec, "exec", 1)
.method(Self::to_string, "toString", 0)
.method(Self::r#match, (JsSymbol::r#match(), "[Symbol.match]"), 1)
.method(
Self::match_all,
(JsSymbol::match_all(), "[Symbol.matchAll]"),
1,
)
.method(Self::replace, (JsSymbol::replace(), "[Symbol.replace]"), 2)
.method(Self::search, (JsSymbol::search(), "[Symbol.search]"), 1)
.method(Self::split, (JsSymbol::split(), "[Symbol.split]"), 2)
.accessor(
utf16!("hasIndices"),
Some(get_has_indices),
None,
flag_attributes,
)
.accessor(utf16!("global"), Some(get_global), None, flag_attributes)
.accessor(
utf16!("ignoreCase"),
Some(get_ignore_case),
None,
flag_attributes,
)
.accessor(
utf16!("multiline"),
Some(get_multiline),
None,
flag_attributes,
)
.accessor(utf16!("dotAll"), Some(get_dot_all), None, flag_attributes)
.accessor(utf16!("unicode"), Some(get_unicode), None, flag_attributes)
.accessor(utf16!("sticky"), Some(get_sticky), None, flag_attributes)
.accessor(utf16!("flags"), Some(get_flags), None, flag_attributes)
.accessor(utf16!("source"), Some(get_source), None, flag_attributes);
let regexp = BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::REGEXP_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::REGEXP_PROTOTYPE_STATIC_SHAPE,
)
.static_accessor(Some(get_species), None)
.property(0)
.method(Self::test, 1)
.method(Self::exec, 1)
.method(Self::to_string, 0)
.method_with_name(Self::r#match, js_string!("[Symbol.match]"), 1)
.method_with_name(Self::match_all, js_string!("[Symbol.matchAll]"), 1)
.method_with_name(Self::replace, js_string!("[Symbol.replace]"), 2)
.method_with_name(Self::search, js_string!("[Symbol.search]"), 1)
.method_with_name(Self::split, js_string!("[Symbol.split]"), 2)
.accessor(Some(get_has_indices), None)
.accessor(Some(get_global), None)
.accessor(Some(get_ignore_case), None)
.accessor(Some(get_multiline), None)
.accessor(Some(get_dot_all), None)
.accessor(Some(get_unicode), None)
.accessor(Some(get_sticky), None)
.accessor(Some(get_flags), None)
.accessor(Some(get_source), None);
#[cfg(feature = "annex-b")]
let regexp = regexp.method(Self::compile, "compile", 2);
let regexp = regexp.method(Self::compile, 2);
regexp.build();
}

61
boa_engine/src/builtins/set/mod.rs

@ -23,10 +23,9 @@ use crate::{
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
error::JsNativeError,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::{Attribute, PropertyNameKind},
property::PropertyNameKind,
realm::Realm,
string::utf16,
symbol::JsSymbol,
Context, JsArgs, JsResult, JsValue,
};
use boa_profiler::Profiler;
@ -56,46 +55,24 @@ impl IntrinsicObject for Set {
.name("values")
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.static_accessor(
JsSymbol::species(),
Some(get_species),
None,
Attribute::CONFIGURABLE,
)
.method(Self::add, "add", 1)
.method(Self::clear, "clear", 0)
.method(Self::delete, "delete", 1)
.method(Self::entries, "entries", 0)
.method(Self::for_each, "forEach", 1)
.method(Self::has, "has", 1)
.property(
utf16!("keys"),
values_function.clone(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.accessor(
utf16!("size"),
Some(size_getter),
None,
Attribute::CONFIGURABLE,
)
.property(
utf16!("values"),
values_function.clone(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
JsSymbol::iterator(),
values_function,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::SET_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::SET_PROTOTYPE_STATIC_SHAPE,
)
.static_accessor(Some(get_species), None)
.method(Self::add, 1)
.method(Self::clear, 0)
.method(Self::delete, 1)
.method(Self::entries, 0)
.method(Self::for_each, 1)
.method(Self::has, 1)
.property(values_function.clone())
.accessor(Some(size_getter), None)
.property(values_function.clone())
.property(values_function)
.property(Self::NAME)
.build();
}
}

133
boa_engine/src/builtins/string/mod.rs

@ -15,7 +15,7 @@ use crate::{
error::JsNativeError,
js_string,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::{Attribute, PropertyDescriptor},
property::PropertyDescriptor,
realm::Realm,
string::utf16,
string::{CodePoint, Utf16Trim},
@ -78,8 +78,6 @@ impl IntrinsicObject for String {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let symbol_iterator = JsSymbol::iterator();
let trim_start = BuiltInBuilder::callable(realm, Self::trim_start)
.length(0)
.name("trimStart")
@ -96,81 +94,68 @@ impl IntrinsicObject for String {
#[cfg(feature = "annex-b")]
let trim_right = trim_end.clone();
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
let builder = BuiltInBuilder::from_standard_constructor::<Self>(realm)
.property(utf16!("length"), 0, attribute)
.property(
utf16!("trimStart"),
trim_start,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
utf16!("trimEnd"),
trim_end,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_method(Self::raw, "raw", 1)
.static_method(Self::from_char_code, "fromCharCode", 1)
.static_method(Self::from_code_point, "fromCodePoint", 1)
.method(Self::char_at, "charAt", 1)
.method(Self::char_code_at, "charCodeAt", 1)
.method(Self::code_point_at, "codePointAt", 1)
.method(Self::to_string, "toString", 0)
.method(Self::concat, "concat", 1)
.method(Self::repeat, "repeat", 1)
.method(Self::slice, "slice", 2)
.method(Self::starts_with, "startsWith", 1)
.method(Self::ends_with, "endsWith", 1)
.method(Self::includes, "includes", 1)
.method(Self::index_of, "indexOf", 1)
.method(Self::last_index_of, "lastIndexOf", 1)
.method(Self::locale_compare, "localeCompare", 1)
.method(Self::r#match, "match", 1)
.method(Self::normalize, "normalize", 0)
.method(Self::pad_end, "padEnd", 1)
.method(Self::pad_start, "padStart", 1)
.method(Self::trim, "trim", 0)
.method(Self::to_case::<false>, "toLowerCase", 0)
.method(Self::to_case::<true>, "toUpperCase", 0)
.method(Self::to_locale_case::<false>, "toLocaleLowerCase", 0)
.method(Self::to_locale_case::<true>, "toLocaleUpperCase", 0)
.method(Self::substring, "substring", 2)
.method(Self::split, "split", 2)
.method(Self::value_of, "valueOf", 0)
.method(Self::match_all, "matchAll", 1)
.method(Self::replace, "replace", 2)
.method(Self::replace_all, "replaceAll", 2)
.method(Self::iterator, (symbol_iterator, "[Symbol.iterator]"), 0)
.method(Self::search, "search", 1)
.method(Self::at, "at", 1);
let builder = BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::STRING_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::STRING_PROTOTYPE_STATIC_SHAPE,
)
.property(0)
.property(trim_start)
.property(trim_end)
.static_method(Self::raw, 1)
.static_method(Self::from_char_code, 1)
.static_method(Self::from_code_point, 1)
.method(Self::char_at, 1)
.method(Self::char_code_at, 1)
.method(Self::code_point_at, 1)
.method(Self::to_string, 0)
.method(Self::concat, 1)
.method(Self::repeat, 1)
.method(Self::slice, 2)
.method(Self::starts_with, 1)
.method(Self::ends_with, 1)
.method(Self::includes, 1)
.method(Self::index_of, 1)
.method(Self::last_index_of, 1)
.method(Self::locale_compare, 1)
.method(Self::r#match, 1)
.method(Self::normalize, 0)
.method(Self::pad_end, 1)
.method(Self::pad_start, 1)
.method(Self::trim, 0)
.method(Self::to_case::<false>, 0)
.method(Self::to_case::<true>, 0)
.method(Self::to_locale_case::<false>, 0)
.method(Self::to_locale_case::<true>, 0)
.method(Self::substring, 2)
.method(Self::split, 2)
.method(Self::value_of, 0)
.method(Self::match_all, 1)
.method(Self::replace, 2)
.method(Self::replace_all, 2)
.method_with_name(Self::iterator, js_string!("[Symbol.iterator]"), 0)
.method(Self::search, 1)
.method(Self::at, 1);
#[cfg(feature = "annex-b")]
{
builder
.property(
utf16!("trimLeft"),
trim_left,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
utf16!("trimRight"),
trim_right,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.method(Self::substr, "substr", 2)
.method(Self::anchor, "anchor", 1)
.method(Self::big, "big", 0)
.method(Self::blink, "blink", 0)
.method(Self::bold, "bold", 0)
.method(Self::fixed, "fixed", 0)
.method(Self::fontcolor, "fontcolor", 1)
.method(Self::fontsize, "fontsize", 1)
.method(Self::italics, "italics", 0)
.method(Self::link, "link", 1)
.method(Self::small, "small", 0)
.method(Self::strike, "strike", 0)
.method(Self::sub, "sub", 0)
.method(Self::sup, "sup", 0)
.property(trim_left)
.property(trim_right)
.method(Self::substr, 2)
.method(Self::anchor, 1)
.method(Self::big, 0)
.method(Self::blink, 0)
.method(Self::bold, 0)
.method(Self::fixed, 0)
.method(Self::fontcolor, 1)
.method(Self::fontsize, 1)
.method(Self::italics, 0)
.method(Self::link, 1)
.method(Self::small, 0)
.method(Self::strike, 0)
.method(Self::sub, 0)
.method(Self::sup, 0)
.build();
}

77
boa_engine/src/builtins/symbol/mod.rs

@ -26,9 +26,7 @@ use crate::{
error::JsNativeError,
js_string,
object::JsObject,
property::Attribute,
realm::Realm,
string::utf16,
symbol::JsSymbol,
value::JsValue,
Context, JsArgs, JsResult, JsString,
@ -109,8 +107,6 @@ impl IntrinsicObject for Symbol {
let symbol_to_string_tag = JsSymbol::to_string_tag();
let symbol_unscopables = JsSymbol::unscopables();
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
let to_primitive = BuiltInBuilder::callable(realm, Self::to_primitive)
.name("[Symbol.toPrimitive]")
.length(1)
@ -120,53 +116,32 @@ impl IntrinsicObject for Symbol {
.name("get description")
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.static_method(Self::for_, "for", 1)
.static_method(Self::key_for, "keyFor", 1)
.static_property(utf16!("asyncIterator"), symbol_async_iterator, attribute)
.static_property(utf16!("hasInstance"), symbol_has_instance, attribute)
.static_property(
utf16!("isConcatSpreadable"),
symbol_is_concat_spreadable,
attribute,
)
.static_property(utf16!("iterator"), symbol_iterator, attribute)
.static_property(utf16!("match"), symbol_match, attribute)
.static_property(utf16!("matchAll"), symbol_match_all, attribute)
.static_property(utf16!("replace"), symbol_replace, attribute)
.static_property(utf16!("search"), symbol_search, attribute)
.static_property(utf16!("species"), symbol_species, attribute)
.static_property(utf16!("split"), symbol_split, attribute)
.static_property(
utf16!("toPrimitive"),
symbol_to_primitive.clone(),
attribute,
)
.static_property(
utf16!("toStringTag"),
symbol_to_string_tag.clone(),
attribute,
)
.static_property(utf16!("unscopables"), symbol_unscopables, attribute)
.method(Self::to_string, "toString", 0)
.method(Self::value_of, "valueOf", 0)
.accessor(
utf16!("description"),
Some(get_description),
None,
Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
)
.property(
symbol_to_string_tag,
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
symbol_to_primitive,
to_primitive,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::SYMBOL_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::SYMBOL_PROTOTYPE_STATIC_SHAPE,
)
.static_method(Self::for_, 1)
.static_method(Self::key_for, 1)
.static_property(symbol_async_iterator)
.static_property(symbol_has_instance)
.static_property(symbol_is_concat_spreadable)
.static_property(symbol_iterator)
.static_property(symbol_match)
.static_property(symbol_match_all)
.static_property(symbol_replace)
.static_property(symbol_search)
.static_property(symbol_species)
.static_property(symbol_split)
.static_property(symbol_to_primitive)
.static_property(symbol_to_string_tag)
.static_property(symbol_unscopables)
.method(Self::to_string, 0)
.method(Self::value_of, 0)
.accessor(Some(get_description), None)
.property(Self::NAME)
.property(to_primitive)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

164
boa_engine/src/builtins/typed_array/mod.rs

@ -26,7 +26,6 @@ use crate::{
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData, ObjectKind},
property::{Attribute, PropertyNameKind},
realm::Realm,
string::utf16,
symbol::JsSymbol,
value::{IntegerOrInfinity, JsValue},
Context, JsArgs, JsResult,
@ -55,34 +54,25 @@ macro_rules! typed_array {
.name("get [Symbol.species]")
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(
realm
.intrinsics()
.constructors()
.typed_array()
.constructor(),
)
.inherits(Some(
realm.intrinsics().constructors().typed_array().prototype(),
))
.static_accessor(
JsSymbol::species(),
Some(get_species),
None,
Attribute::CONFIGURABLE,
)
.property(
utf16!("BYTES_PER_ELEMENT"),
TypedArrayKind::$variant.element_size(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
)
.static_property(
utf16!("BYTES_PER_ELEMENT"),
TypedArrayKind::$variant.element_size(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::TYPED_ARRAY_INSTANCE_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::TYPED_ARRAY_INSTANCE_PROTOTYPE_STATIC_SHAPE,
)
.prototype(
realm
.intrinsics()
.constructors()
.typed_array()
.constructor(),
)
.inherits(Some(
realm.intrinsics().constructors().typed_array().prototype(),
))
.static_accessor(Some(get_species), None)
.property(TypedArrayKind::$variant.element_size())
.static_property(TypedArrayKind::$variant.element_size())
.build();
}
}
@ -269,79 +259,49 @@ impl IntrinsicObject for TypedArray {
.length(0)
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.static_accessor(
JsSymbol::species(),
Some(get_species),
None,
Attribute::CONFIGURABLE,
)
.property(
JsSymbol::iterator(),
values_function,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.accessor(
utf16!("buffer"),
Some(get_buffer),
None,
Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
)
.accessor(
utf16!("byteLength"),
Some(get_byte_length),
None,
Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
)
.accessor(
utf16!("byteOffset"),
Some(get_byte_offset),
None,
Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
)
.accessor(
utf16!("length"),
Some(get_length),
None,
Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
)
.accessor(
JsSymbol::to_string_tag(),
Some(get_to_string_tag),
None,
Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
)
.static_method(Self::from, "from", 1)
.static_method(Self::of, "of", 0)
.method(Self::at, "at", 1)
.method(Self::copy_within, "copyWithin", 2)
.method(Self::entries, "entries", 0)
.method(Self::every, "every", 1)
.method(Self::fill, "fill", 1)
.method(Self::filter, "filter", 1)
.method(Self::find, "find", 1)
.method(Self::findindex, "findIndex", 1)
.method(Self::foreach, "forEach", 1)
.method(Self::includes, "includes", 1)
.method(Self::index_of, "indexOf", 1)
.method(Self::join, "join", 1)
.method(Self::keys, "keys", 0)
.method(Self::last_index_of, "lastIndexOf", 1)
.method(Self::map, "map", 1)
.method(Self::reduce, "reduce", 1)
.method(Self::reduceright, "reduceRight", 1)
.method(Self::reverse, "reverse", 0)
.method(Self::set, "set", 1)
.method(Self::slice, "slice", 2)
.method(Self::some, "some", 1)
.method(Self::sort, "sort", 1)
.method(Self::subarray, "subarray", 2)
.method(Self::values, "values", 0)
// 23.2.3.29 %TypedArray%.prototype.toString ( )
// The initial value of the %TypedArray%.prototype.toString data property is the same
// built-in function object as the Array.prototype.toString method defined in 23.1.3.30.
.method(Array::to_string, "toString", 0)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::TYPED_ARRAY_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::TYPED_ARRAY_PROTOTYPE_STATIC_SHAPE,
)
.static_accessor(Some(get_species), None)
.property(values_function)
.accessor(Some(get_buffer), None)
.accessor(Some(get_byte_length), None)
.accessor(Some(get_byte_offset), None)
.accessor(Some(get_length), None)
.accessor(Some(get_to_string_tag), None)
.static_method(Self::from, 1)
.static_method(Self::of, 0)
.method(Self::at, 1)
.method(Self::copy_within, 2)
.method(Self::entries, 0)
.method(Self::every, 1)
.method(Self::fill, 1)
.method(Self::filter, 1)
.method(Self::find, 1)
.method(Self::findindex, 1)
.method(Self::foreach, 1)
.method(Self::includes, 1)
.method(Self::index_of, 1)
.method(Self::join, 1)
.method(Self::keys, 0)
.method(Self::last_index_of, 1)
.method(Self::map, 1)
.method(Self::reduce, 1)
.method(Self::reduceright, 1)
.method(Self::reverse, 0)
.method(Self::set, 1)
.method(Self::slice, 2)
.method(Self::some, 1)
.method(Self::sort, 1)
.method(Self::subarray, 2)
.method(Self::values, 0)
// 23.2.3.29 %TypedArray%.prototype.toString ( )
// The initial value of the %TypedArray%.prototype.toString data property is the same
// built-in function object as the Array.prototype.toString method defined in 23.1.3.30.
.method(Array::to_string, 0)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {

16
boa_engine/src/builtins/uri/mod.rs

@ -50,10 +50,10 @@ pub struct UriFunctions {
impl Default for UriFunctions {
fn default() -> Self {
Self {
decode_uri: JsFunction::empty_intrinsic_function(false),
decode_uri_component: JsFunction::empty_intrinsic_function(false),
encode_uri: JsFunction::empty_intrinsic_function(false),
encode_uri_component: JsFunction::empty_intrinsic_function(false),
decode_uri: JsFunction::empty_intrinsic_function_static_shape(false),
decode_uri_component: JsFunction::empty_intrinsic_function_static_shape(false),
encode_uri: JsFunction::empty_intrinsic_function_static_shape(false),
encode_uri_component: JsFunction::empty_intrinsic_function_static_shape(false),
}
}
}
@ -82,7 +82,7 @@ pub(crate) struct DecodeUri;
impl IntrinsicObject for DecodeUri {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, decode_uri)
BuiltInBuilder::callable_intrinsic::<Self>(realm, decode_uri)
.name(Self::NAME)
.length(1)
.build();
@ -100,7 +100,7 @@ pub(crate) struct DecodeUriComponent;
impl IntrinsicObject for DecodeUriComponent {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, decode_uri_component)
BuiltInBuilder::callable_intrinsic::<Self>(realm, decode_uri_component)
.name(Self::NAME)
.length(1)
.build();
@ -122,7 +122,7 @@ pub(crate) struct EncodeUri;
impl IntrinsicObject for EncodeUri {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, encode_uri)
BuiltInBuilder::callable_intrinsic::<Self>(realm, encode_uri)
.name(Self::NAME)
.length(1)
.build();
@ -139,7 +139,7 @@ pub(crate) struct EncodeUriComponent;
impl IntrinsicObject for EncodeUriComponent {
fn init(realm: &Realm) {
BuiltInBuilder::callable_with_intrinsic::<Self>(realm, encode_uri_component)
BuiltInBuilder::callable_intrinsic::<Self>(realm, encode_uri_component)
.name(Self::NAME)
.length(1)
.build();

18
boa_engine/src/builtins/weak/weak_ref.rs

@ -1,4 +1,5 @@
use boa_gc::{Finalize, Trace, WeakGc};
use boa_macros::utf16;
use boa_profiler::Profiler;
use crate::{
@ -7,7 +8,6 @@ use crate::{
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::Attribute,
realm::Realm,
symbol::JsSymbol,
Context, JsArgs, JsNativeError, JsResult, JsValue,
};
@ -31,14 +31,14 @@ impl IntrinsicObject for WeakRef {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.property(
JsSymbol::to_string_tag(),
"WeakRef",
Attribute::CONFIGURABLE,
)
.method(Self::deref, "deref", 0)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::WEAK_REF_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::WEAK_REF_PROTOTYPE_STATIC_SHAPE,
)
.property(utf16!("WeakRef"))
.method(Self::deref, 0)
.build();
}
}

23
boa_engine/src/builtins/weak_map/mod.rs

@ -17,7 +17,6 @@ use crate::{
property::Attribute,
realm::Realm,
string::utf16,
symbol::JsSymbol,
Context, JsArgs, JsNativeError, JsResult, JsValue,
};
use boa_gc::{Finalize, Trace};
@ -33,17 +32,17 @@ impl IntrinsicObject for WeakMap {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.method(Self::delete, "delete", 1)
.method(Self::get, "get", 1)
.method(Self::has, "has", 1)
.method(Self::set, "set", 2)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::WEAK_MAP_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::WEAK_MAP_PROTOTYPE_STATIC_SHAPE,
)
.property(Self::NAME)
.method(Self::delete, 1)
.method(Self::get, 1)
.method(Self::has, 1)
.method(Self::set, 2)
.build();
}
}

21
boa_engine/src/builtins/weak_set/mod.rs

@ -14,7 +14,6 @@ use crate::{
property::Attribute,
realm::Realm,
string::utf16,
symbol::JsSymbol,
Context, JsArgs, JsNativeError, JsResult, JsValue,
};
use boa_gc::{Finalize, Trace, WeakMap};
@ -30,16 +29,16 @@ impl IntrinsicObject for WeakSet {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(Self::NAME, "init");
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.method(Self::add, "add", 1)
.method(Self::delete, "delete", 1)
.method(Self::has, "has", 1)
.build();
BuiltInBuilder::from_standard_constructor_static_shape::<Self>(
realm,
&boa_builtins::WEAK_SET_CONSTRUCTOR_STATIC_SHAPE,
&boa_builtins::WEAK_SET_PROTOTYPE_STATIC_SHAPE,
)
.property(Self::NAME)
.method(Self::add, 1)
.method(Self::delete, 1)
.method(Self::has, 1)
.build();
}
}

130
boa_engine/src/context/intrinsics.rs

@ -75,11 +75,18 @@ impl StandardConstructor {
/// Build a constructor with a defined prototype.
fn with_prototype(prototype: JsObject) -> Self {
Self {
constructor: JsFunction::empty_intrinsic_function(true),
constructor: JsFunction::empty_intrinsic_function_static_shape(true),
prototype,
}
}
fn default_static_shape() -> Self {
Self {
constructor: JsFunction::empty_intrinsic_function_static_shape(true),
prototype: JsObject::default_with_static_shape(),
}
}
/// Return the prototype of the constructor object.
///
/// This is the same as `Object.prototype`, `Array.prototype`, etc
@ -156,67 +163,62 @@ pub struct StandardConstructors {
impl Default for StandardConstructors {
fn default() -> Self {
Self {
object: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
None,
ObjectData::object_prototype(),
)),
object: StandardConstructor::with_prototype(
JsObject::from_data_and_empty_static_shape(ObjectData::object_prototype()),
),
async_generator_function: StandardConstructor::default(),
proxy: StandardConstructor::default(),
date: StandardConstructor::default(),
date: StandardConstructor::default_static_shape(),
function: StandardConstructor {
constructor: JsFunction::empty_intrinsic_function(true),
prototype: JsFunction::empty_intrinsic_function(false).into(),
constructor: JsFunction::empty_intrinsic_function_static_shape(true),
prototype: JsFunction::empty_intrinsic_function_static_shape(false).into(),
},
async_function: StandardConstructor::default(),
generator_function: StandardConstructor::default(),
array: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
None,
array: StandardConstructor::with_prototype(JsObject::from_data_and_empty_static_shape(
ObjectData::array(),
)),
bigint: StandardConstructor::default(),
number: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
None,
ObjectData::number(0.0),
)),
boolean: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
None,
ObjectData::boolean(false),
)),
string: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
None,
ObjectData::string("".into()),
)),
regexp: StandardConstructor::default(),
symbol: StandardConstructor::default(),
error: StandardConstructor::default(),
type_error: StandardConstructor::default(),
reference_error: StandardConstructor::default(),
range_error: StandardConstructor::default(),
syntax_error: StandardConstructor::default(),
eval_error: StandardConstructor::default(),
uri_error: StandardConstructor::default(),
aggregate_error: StandardConstructor::default(),
map: StandardConstructor::default(),
set: StandardConstructor::default(),
typed_array: StandardConstructor::default(),
typed_int8_array: StandardConstructor::default(),
typed_uint8_array: StandardConstructor::default(),
typed_uint8clamped_array: StandardConstructor::default(),
typed_int16_array: StandardConstructor::default(),
typed_uint16_array: StandardConstructor::default(),
typed_int32_array: StandardConstructor::default(),
typed_uint32_array: StandardConstructor::default(),
typed_bigint64_array: StandardConstructor::default(),
typed_biguint64_array: StandardConstructor::default(),
typed_float32_array: StandardConstructor::default(),
typed_float64_array: StandardConstructor::default(),
array_buffer: StandardConstructor::default(),
data_view: StandardConstructor::default(),
bigint: StandardConstructor::default_static_shape(),
number: StandardConstructor::with_prototype(
JsObject::from_data_and_empty_static_shape(ObjectData::number(0.0)),
),
boolean: StandardConstructor::with_prototype(
JsObject::from_data_and_empty_static_shape(ObjectData::boolean(false)),
),
string: StandardConstructor::with_prototype(
JsObject::from_data_and_empty_static_shape(ObjectData::string("".into())),
),
regexp: StandardConstructor::default_static_shape(),
symbol: StandardConstructor::default_static_shape(),
error: StandardConstructor::default_static_shape(),
type_error: StandardConstructor::default_static_shape(),
reference_error: StandardConstructor::default_static_shape(),
range_error: StandardConstructor::default_static_shape(),
syntax_error: StandardConstructor::default_static_shape(),
eval_error: StandardConstructor::default_static_shape(),
uri_error: StandardConstructor::default_static_shape(),
aggregate_error: StandardConstructor::default_static_shape(),
map: StandardConstructor::default_static_shape(),
set: StandardConstructor::default_static_shape(),
typed_array: StandardConstructor::default_static_shape(),
typed_int8_array: StandardConstructor::default_static_shape(),
typed_uint8_array: StandardConstructor::default_static_shape(),
typed_uint8clamped_array: StandardConstructor::default_static_shape(),
typed_int16_array: StandardConstructor::default_static_shape(),
typed_uint16_array: StandardConstructor::default_static_shape(),
typed_int32_array: StandardConstructor::default_static_shape(),
typed_uint32_array: StandardConstructor::default_static_shape(),
typed_bigint64_array: StandardConstructor::default_static_shape(),
typed_biguint64_array: StandardConstructor::default_static_shape(),
typed_float32_array: StandardConstructor::default_static_shape(),
typed_float64_array: StandardConstructor::default_static_shape(),
array_buffer: StandardConstructor::default_static_shape(),
data_view: StandardConstructor::default_static_shape(),
date_time_format: StandardConstructor::default(),
promise: StandardConstructor::default(),
weak_ref: StandardConstructor::default(),
weak_map: StandardConstructor::default(),
weak_set: StandardConstructor::default(),
promise: StandardConstructor::default_static_shape(),
weak_ref: StandardConstructor::default_static_shape(),
weak_map: StandardConstructor::default_static_shape(),
weak_set: StandardConstructor::default_static_shape(),
#[cfg(feature = "intl")]
collator: StandardConstructor::default(),
#[cfg(feature = "intl")]
@ -817,24 +819,24 @@ pub struct IntrinsicObjects {
impl Default for IntrinsicObjects {
fn default() -> Self {
Self {
reflect: JsObject::default(),
math: JsObject::default(),
json: JsObject::default(),
reflect: JsObject::default_with_static_shape(),
math: JsObject::default_with_static_shape(),
json: JsObject::default_with_static_shape(),
throw_type_error: JsFunction::empty_intrinsic_function(false),
array_prototype_values: JsFunction::empty_intrinsic_function(false),
array_prototype_values: JsFunction::empty_intrinsic_function_static_shape(false),
iterator_prototypes: IteratorPrototypes::default(),
generator: JsObject::default(),
async_generator: JsObject::default(),
eval: JsFunction::empty_intrinsic_function(false),
eval: JsFunction::empty_intrinsic_function_static_shape(false),
uri_functions: UriFunctions::default(),
is_finite: JsFunction::empty_intrinsic_function(false),
is_nan: JsFunction::empty_intrinsic_function(false),
parse_float: JsFunction::empty_intrinsic_function(false),
parse_int: JsFunction::empty_intrinsic_function(false),
is_finite: JsFunction::empty_intrinsic_function_static_shape(false),
is_nan: JsFunction::empty_intrinsic_function_static_shape(false),
parse_float: JsFunction::empty_intrinsic_function_static_shape(false),
parse_int: JsFunction::empty_intrinsic_function_static_shape(false),
#[cfg(feature = "annex-b")]
escape: JsFunction::empty_intrinsic_function(false),
escape: JsFunction::empty_intrinsic_function_static_shape(false),
#[cfg(feature = "annex-b")]
unescape: JsFunction::empty_intrinsic_function(false),
unescape: JsFunction::empty_intrinsic_function_static_shape(false),
#[cfg(feature = "intl")]
intl: JsObject::default(),
#[cfg(feature = "intl")]

13
boa_engine/src/object/builtins/jsfunction.rs

@ -40,6 +40,19 @@ impl JsFunction {
}
}
pub(crate) fn empty_intrinsic_function_static_shape(constructor: bool) -> Self {
Self {
inner: JsObject::from_object_and_vtable(
Object::with_empty_shape(),
if constructor {
&CONSTRUCTOR_INTERNAL_METHODS
} else {
&FUNCTION_INTERNAL_METHODS
},
),
}
}
/// Creates a [`JsFunction`] from a [`JsObject`], or returns `None` if the object is not a function.
///
/// This does not clone the fields of the function, it only does a shallow clone of the object.

25
boa_engine/src/object/jsobject.rs

@ -4,7 +4,7 @@
use super::{
internal_methods::{InternalObjectMethods, ARRAY_EXOTIC_INTERNAL_METHODS},
shape::RootShape,
shape::{static_shape::StaticShape, RootShape},
JsPrototype, NativeObject, Object, PrivateName, PropertyMap,
};
use crate::{
@ -60,6 +60,12 @@ impl Default for JsObject {
}
impl JsObject {
/// TODO: doc
pub(crate) fn default_with_static_shape() -> Self {
let data = ObjectData::ordinary();
Self::from_object_and_vtable(Object::with_empty_shape(), data.internal_methods)
}
/// Creates a new `JsObject` from its inner object and its vtable.
pub(crate) fn from_object_and_vtable(
object: Object,
@ -120,6 +126,23 @@ impl JsObject {
}
}
pub(crate) fn from_data_and_empty_static_shape(data: ObjectData) -> Self {
Self {
inner: Gc::new(VTableObject {
object: GcRefCell::new(Object {
kind: data.kind,
properties: PropertyMap::new(
StaticShape::new(&boa_builtins::EMPTY_OBJECT_STATIC_SHAPE).into(),
ThinVec::default(),
),
extensible: true,
private_elements: ThinVec::new(),
}),
vtable: data.internal_methods,
}),
}
}
/// Creates a new object with the provided prototype and object data.
///
/// This is equivalent to calling the specification's abstract operation [`OrdinaryObjectCreate`],

29
boa_engine/src/object/mod.rs

@ -26,7 +26,7 @@ use self::{
string::STRING_EXOTIC_INTERNAL_METHODS,
InternalObjectMethods, ORDINARY_INTERNAL_METHODS,
},
shape::Shape,
shape::{static_shape::StaticShape, Shape},
};
#[cfg(feature = "intl")]
use crate::builtins::intl::{
@ -873,6 +873,18 @@ impl Debug for ObjectKind {
}
impl Object {
fn with_empty_shape() -> Self {
Self {
kind: ObjectKind::Ordinary,
properties: PropertyMap::new(
StaticShape::new(&boa_builtins::EMPTY_OBJECT_STATIC_SHAPE).into(),
ThinVec::default(),
),
extensible: true,
private_elements: ThinVec::new(),
}
}
/// Returns a mutable reference to the kind of an object.
pub(crate) fn kind_mut(&mut self) -> &mut ObjectKind {
&mut self.kind
@ -1524,6 +1536,12 @@ impl Object {
/// Gets the prototype instance of this object.
#[inline]
pub fn prototype(&self) -> JsPrototype {
// If it is static then the prototype is stored on the (len - 1) position.
if self.properties.shape.is_static() {
return self.properties.storage[self.properties.storage.len() - 1]
.as_object()
.cloned();
}
self.properties.shape.prototype()
}
@ -1536,7 +1554,14 @@ impl Object {
pub fn set_prototype<O: Into<JsPrototype>>(&mut self, prototype: O) -> bool {
let prototype = prototype.into();
if self.extensible {
self.properties.shape = self.properties.shape.change_prototype_transition(prototype);
if let Some(shape) = self.properties.shape.as_static() {
self.properties.storage.pop();
self.properties.shape = shape.to_unique(prototype).into();
} else {
self.properties.shape =
self.properties.shape.change_prototype_transition(prototype);
}
true
} else {
// If target is non-extensible, [[SetPrototypeOf]] must return false

38
boa_engine/src/object/property_map.rs

@ -314,7 +314,21 @@ impl PropertyMap {
property_key: key.clone(),
attributes,
};
let transition = self.shape.change_attributes_transition(key);
let transition = if let Some(shape) = self.shape.as_static() {
let prototype = self
.storage
.pop()
.as_ref()
.and_then(JsValue::as_object)
.cloned();
shape
.to_unique(prototype)
.change_attributes_transition(&key)
} else {
self.shape.change_attributes_transition(key)
};
self.shape = transition.shape;
match transition.action {
ChangeTransitionAction::Nothing => {}
@ -349,6 +363,17 @@ impl PropertyMap {
return true;
}
// TODO: optimization, we could inline `insert_property_transition` to avoid the check
if let Some(shape) = self.shape.as_static() {
let prototype = self
.storage
.pop()
.as_ref()
.and_then(JsValue::as_object)
.cloned();
self.shape = shape.to_unique(prototype).into();
}
let transition_key = TransitionKey {
property_key: key.clone(),
attributes,
@ -393,6 +418,17 @@ impl PropertyMap {
return self.indexed_properties.remove(*index);
}
if let Some(slot) = self.shape.lookup(key) {
if let Some(shape) = self.shape.as_static() {
let prototype = self
.storage
.pop()
.as_ref()
.and_then(JsValue::as_object)
.cloned();
self.shape = shape.to_unique(prototype).into();
}
// shift all elements when removing.
if slot.attributes.is_accessor_descriptor() {
self.storage.remove(slot.index as usize + 1);

36
boa_engine/src/object/shape/mod.rs

@ -4,6 +4,7 @@ pub(crate) mod property_table;
mod root_shape;
pub(crate) mod shared_shape;
pub(crate) mod slot;
pub(crate) mod static_shape;
pub(crate) mod unique_shape;
pub use root_shape::RootShape;
@ -16,7 +17,7 @@ use boa_gc::{Finalize, Trace};
use crate::property::PropertyKey;
use self::{shared_shape::TransitionKey, slot::Slot};
use self::{shared_shape::TransitionKey, slot::Slot, static_shape::StaticShape};
use super::JsPrototype;
@ -56,6 +57,7 @@ pub(crate) struct ChangeTransition<T> {
enum Inner {
Unique(UniqueShape),
Shared(SharedShape),
Static(StaticShape),
}
/// Represents the shape of an object.
@ -84,12 +86,26 @@ impl Shape {
matches!(self.inner, Inner::Shared(_))
}
/// Returns `true` if it's a static shape, `false` otherwise.
pub(crate) const fn as_static(&self) -> Option<&StaticShape> {
if let Inner::Static(shape) = &self.inner {
return Some(shape);
}
None
}
/// Returns `true` if it's a unique shape, `false` otherwise.
#[inline]
pub const fn is_unique(&self) -> bool {
matches!(self.inner, Inner::Unique(_))
}
/// Returns `true` if it's a static shape, `false` otherwise.
#[inline]
pub const fn is_static(&self) -> bool {
matches!(self.inner, Inner::Static(_))
}
pub(crate) const fn as_unique(&self) -> Option<&UniqueShape> {
if let Inner::Unique(shape) = &self.inner {
return Some(shape);
@ -110,6 +126,7 @@ impl Shape {
shape.into()
}
Inner::Unique(shape) => shape.insert_property_transition(key).into(),
Inner::Static(shape) => shape.insert_property_transition(key).into(),
}
}
@ -136,6 +153,7 @@ impl Shape {
}
}
Inner::Unique(shape) => shape.change_attributes_transition(&key),
Inner::Static(shape) => shape.change_attributes_transition(&key),
}
}
@ -152,6 +170,7 @@ impl Shape {
shape.into()
}
Inner::Unique(shape) => shape.remove_property_transition(key).into(),
Inner::Static(shape) => shape.remove_property_transition(key).into(),
}
}
@ -166,14 +185,16 @@ impl Shape {
shape.into()
}
Inner::Unique(shape) => shape.change_prototype_transition(prototype).into(),
Inner::Static(shape) => shape.change_prototype_transition(prototype).into(),
}
}
/// Get the [`JsPrototype`] of the [`Shape`].
pub fn prototype(&self) -> JsPrototype {
pub(crate) fn prototype(&self) -> JsPrototype {
match &self.inner {
Inner::Shared(shape) => shape.prototype(),
Inner::Unique(shape) => shape.prototype(),
Inner::Static(_) => unreachable!("Static shapes don't have prototypes in them"),
}
}
@ -183,6 +204,7 @@ impl Shape {
match &self.inner {
Inner::Shared(shape) => shape.lookup(key),
Inner::Unique(shape) => shape.lookup(key),
Inner::Static(shape) => shape.lookup(key),
}
}
@ -192,6 +214,7 @@ impl Shape {
match &self.inner {
Inner::Shared(shape) => shape.keys(),
Inner::Unique(shape) => shape.keys(),
Inner::Static(shape) => shape.keys(),
}
}
@ -201,6 +224,7 @@ impl Shape {
match &self.inner {
Inner::Shared(shape) => shape.to_addr_usize(),
Inner::Unique(shape) => shape.to_addr_usize(),
Inner::Static(shape) => shape.to_addr_usize(),
}
}
}
@ -220,3 +244,11 @@ impl From<SharedShape> for Shape {
}
}
}
impl From<StaticShape> for Shape {
fn from(shape: StaticShape) -> Self {
Self {
inner: Inner::Static(shape),
}
}
}

2
boa_engine/src/object/shape/slot.rs

@ -42,7 +42,7 @@ impl SlotAttributes {
///
/// Slots can have different width depending on its attributes, accessors properties have width `2`,
/// while data properties have width `1`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct Slot {
pub(crate) index: SlotIndex,
pub(crate) attributes: SlotAttributes,

149
boa_engine/src/object/shape/static_shape.rs

@ -0,0 +1,149 @@
// Temp allow
#![allow(dead_code)]
#![allow(clippy::needless_pass_by_value)]
use std::fmt::Debug;
use boa_builtins::{EncodedStaticPropertyKey, StaticPropertyKey};
use boa_gc::{Finalize, Trace};
use crate::{
object::shape::property_table::PropertyTableInner, property::PropertyKey, symbol::WellKnown,
JsString, JsSymbol,
};
use super::{
shared_shape::TransitionKey, slot::SlotAttributes, ChangeTransition, JsPrototype, Shape, Slot,
UniqueShape,
};
pub(crate) type StaticShapeInner = &'static boa_builtins::StaticShape;
/// TODO: doc
fn from_static_property_key(key: StaticPropertyKey) -> PropertyKey {
match key {
boa_builtins::StaticPropertyKey::String(index) => {
PropertyKey::String(unsafe { JsString::from_index(index) })
}
boa_builtins::StaticPropertyKey::Symbol(s) => {
let symbol = match WellKnown::try_from(s).expect("should be an well known symbol") {
WellKnown::AsyncIterator => JsSymbol::async_iterator(),
WellKnown::HasInstance => JsSymbol::has_instance(),
WellKnown::IsConcatSpreadable => JsSymbol::is_concat_spreadable(),
WellKnown::Iterator => JsSymbol::iterator(),
WellKnown::Match => JsSymbol::r#match(),
WellKnown::MatchAll => JsSymbol::match_all(),
WellKnown::Replace => JsSymbol::replace(),
WellKnown::Search => JsSymbol::search(),
WellKnown::Species => JsSymbol::species(),
WellKnown::Split => JsSymbol::split(),
WellKnown::ToPrimitive => JsSymbol::to_primitive(),
WellKnown::ToStringTag => JsSymbol::to_string_tag(),
WellKnown::Unscopables => JsSymbol::unscopables(),
};
PropertyKey::Symbol(symbol)
}
}
}
/// TODO: doc
fn to_static_property_key(key: &PropertyKey) -> Option<StaticPropertyKey> {
match key {
PropertyKey::String(s) => Some(StaticPropertyKey::String(s.as_static_string_index()?)),
PropertyKey::Symbol(s) => Some(StaticPropertyKey::Symbol(s.hash().try_into().ok()?)),
PropertyKey::Index(_) => None,
}
}
/// Represents a [`Shape`] that is not shared with any other object.
///
/// This is useful for objects that are inherently unique like,
/// the builtin object.
///
/// Cloning this does a shallow clone.
#[derive(Debug, Clone, Trace, Finalize)]
pub(crate) struct StaticShape {
inner: StaticShapeInner,
}
impl StaticShape {
/// Create a new [`UniqueShape`].
pub(crate) const fn new(inner: StaticShapeInner) -> Self {
Self { inner }
}
/// Inserts a new property into the [`UniqueShape`].
pub(crate) fn insert_property_transition(&self, _key: TransitionKey) -> UniqueShape {
todo!()
}
/// Remove a property from the [`UniqueShape`].
///
/// This will cause the current shape to be invalidated, and a new [`UniqueShape`] will be returned.
pub(crate) fn remove_property_transition(&self, _key: &PropertyKey) -> UniqueShape {
todo!()
}
/// Does a property lookup on the [`UniqueShape`] returning the [`Slot`] where it's
/// located or [`None`] otherwise.
pub(crate) fn lookup(&self, key: &PropertyKey) -> Option<Slot> {
let key = to_static_property_key(key)?;
let (index, attributes) = self.inner.get(key)?;
Some(Slot {
index: u32::from(index),
attributes: SlotAttributes::from_bits_retain(attributes.bits()),
})
}
/// Change the attributes of a property from the [`UniqueShape`].
///
/// This will cause the current shape to be invalidated, and a new [`UniqueShape`] will be returned.
///
/// NOTE: This assumes that the property had already been inserted.
pub(crate) fn change_attributes_transition(
&self,
_key: &TransitionKey,
) -> ChangeTransition<Shape> {
todo!()
}
/// Change the prototype of the [`UniqueShape`].
///
/// This will cause the current shape to be invalidated, and a new [`UniqueShape`] will be returned.
pub(crate) fn change_prototype_transition(&self, _prototype: JsPrototype) -> UniqueShape {
todo!()
}
/// Gets all keys first strings then symbols in creation order.
pub(crate) fn keys(&self) -> Vec<PropertyKey> {
self.inner
.property_table
.keys()
.map(EncodedStaticPropertyKey::decode)
.map(from_static_property_key)
.collect()
}
/// TODO: doc
pub(crate) fn to_unique(&self, prototype: JsPrototype) -> UniqueShape {
// TODO: optimization, preallocate capacity.
// TODO: optimization, direct iniitialize the map.
let mut property_table = PropertyTableInner::default();
for (key, (_, slot_attributes)) in &self.inner.property_table {
property_table.insert(
from_static_property_key(key.decode()),
SlotAttributes::from_bits_retain(slot_attributes.bits()),
);
}
UniqueShape::new(prototype, property_table)
}
/// Return location in memory of the [`UniqueShape`].
pub(crate) fn to_addr_usize(&self) -> usize {
let ptr: *const _ = self.inner;
ptr as usize
}
}

465
boa_engine/src/string/common.rs

@ -6,6 +6,8 @@ use super::JsString;
use boa_macros::utf16;
use rustc_hash::{FxHashMap, FxHasher};
use boa_builtins::RAW_STATICS;
macro_rules! well_known_statics {
( $( $(#[$attr:meta])* ($name:ident, $string:literal) ),+$(,)? ) => {
$(
@ -134,466 +136,3 @@ thread_local! {
constants
};
}
/// Array of raw static strings that aren't reference counted.
///
/// The macro `static_strings` automatically sorts the array of strings, making it faster
/// for searches by using `binary_search`.
const RAW_STATICS: &[&[u16]] = &[
utf16!(""),
// Misc
utf16!(","),
utf16!(":"),
// Generic use
utf16!("name"),
utf16!("length"),
utf16!("arguments"),
utf16!("prototype"),
utf16!("constructor"),
utf16!("return"),
utf16!("throw"),
utf16!("global"),
utf16!("globalThis"),
// typeof
utf16!("null"),
utf16!("undefined"),
utf16!("number"),
utf16!("string"),
utf16!("symbol"),
utf16!("bigint"),
utf16!("object"),
utf16!("function"),
// Property descriptor
utf16!("value"),
utf16!("get"),
utf16!("set"),
utf16!("writable"),
utf16!("enumerable"),
utf16!("configurable"),
// Object object
utf16!("Object"),
utf16!("assign"),
utf16!("create"),
utf16!("toString"),
utf16!("valueOf"),
utf16!("is"),
utf16!("seal"),
utf16!("isSealed"),
utf16!("freeze"),
utf16!("isFrozen"),
utf16!("isExtensible"),
utf16!("hasOwnProperty"),
utf16!("isPrototypeOf"),
utf16!("setPrototypeOf"),
utf16!("getPrototypeOf"),
utf16!("defineProperty"),
utf16!("defineProperties"),
utf16!("deleteProperty"),
utf16!("construct"),
utf16!("hasOwn"),
utf16!("ownKeys"),
utf16!("keys"),
utf16!("values"),
utf16!("entries"),
utf16!("fromEntries"),
// Function object
utf16!("Function"),
utf16!("apply"),
utf16!("bind"),
utf16!("call"),
// Generator object
utf16!("Generator"),
// Array object
utf16!("Array"),
utf16!("at"),
utf16!("from"),
utf16!("isArray"),
utf16!("of"),
utf16!("copyWithin"),
utf16!("every"),
utf16!("fill"),
utf16!("filter"),
utf16!("find"),
utf16!("findIndex"),
utf16!("findLast"),
utf16!("findLastIndex"),
utf16!("flat"),
utf16!("flatMap"),
utf16!("forEach"),
utf16!("includes"),
utf16!("indexOf"),
utf16!("join"),
utf16!("map"),
utf16!("next"),
utf16!("reduce"),
utf16!("reduceRight"),
utf16!("reverse"),
utf16!("shift"),
utf16!("slice"),
utf16!("splice"),
utf16!("some"),
utf16!("sort"),
utf16!("unshift"),
utf16!("push"),
utf16!("pop"),
// String object
utf16!("String"),
utf16!("charAt"),
utf16!("charCodeAt"),
utf16!("codePointAt"),
utf16!("concat"),
utf16!("endsWith"),
utf16!("fromCharCode"),
utf16!("fromCodePoint"),
utf16!("lastIndexOf"),
utf16!("match"),
utf16!("matchAll"),
utf16!("normalize"),
utf16!("padEnd"),
utf16!("padStart"),
utf16!("raw"),
utf16!("repeat"),
utf16!("replace"),
utf16!("replaceAll"),
utf16!("search"),
utf16!("split"),
utf16!("startsWith"),
utf16!("substr"),
utf16!("substring"),
utf16!("toLocaleString"),
utf16!("toLowerCase"),
utf16!("toUpperCase"),
utf16!("trim"),
utf16!("trimEnd"),
utf16!("trimStart"),
// Number object
utf16!("Number"),
utf16!("Infinity"),
utf16!("NaN"),
utf16!("parseInt"),
utf16!("parseFloat"),
utf16!("isFinite"),
utf16!("isNaN"),
utf16!("EPSILON"),
utf16!("MAX_SAFE_INTEGER"),
utf16!("MIN_SAFE_INTEGER"),
utf16!("MAX_VALUE"),
utf16!("MIN_VALUE"),
utf16!("isSafeInteger"),
utf16!("isInteger"),
utf16!("toExponential"),
utf16!("toFixed"),
utf16!("toPrecision"),
// Boolean object
utf16!("Boolean"),
// BigInt object
utf16!("BigInt"),
utf16!("asIntN"),
utf16!("asUintN"),
// RegExp object
utf16!("RegExp"),
utf16!("exec"),
utf16!("test"),
utf16!("flags"),
utf16!("index"),
utf16!("lastIndex"),
utf16!("hasIndices"),
utf16!("ignoreCase"),
utf16!("multiline"),
utf16!("dotAll"),
utf16!("unicode"),
utf16!("sticky"),
utf16!("source"),
utf16!("get hasIndices"),
utf16!("get global"),
utf16!("get ignoreCase"),
utf16!("get multiline"),
utf16!("get dotAll"),
utf16!("get unicode"),
utf16!("get sticky"),
utf16!("get flags"),
utf16!("get source"),
// Symbol object
utf16!("Symbol"),
utf16!("for"),
utf16!("keyFor"),
utf16!("description"),
utf16!("asyncIterator"),
utf16!("hasInstance"),
utf16!("species"),
utf16!("unscopables"),
utf16!("iterator"),
utf16!("toStringTag"),
utf16!("toPrimitive"),
utf16!("get description"),
// Map object
utf16!("Map"),
utf16!("clear"),
utf16!("delete"),
utf16!("has"),
utf16!("size"),
// Set object
utf16!("Set"),
utf16!("add"),
// Reflect object
utf16!("Reflect"),
// Proxy object
utf16!("Proxy"),
utf16!("revocable"),
// Error objects
utf16!("Error"),
utf16!("AggregateError"),
utf16!("TypeError"),
utf16!("RangeError"),
utf16!("SyntaxError"),
utf16!("ReferenceError"),
utf16!("EvalError"),
utf16!("ThrowTypeError"),
utf16!("URIError"),
utf16!("message"),
// Date object
utf16!("Date"),
utf16!("toJSON"),
utf16!("getDate"),
utf16!("getDay"),
utf16!("getFullYear"),
utf16!("getHours"),
utf16!("getMilliseconds"),
utf16!("getMinutes"),
utf16!("getMonth"),
utf16!("getSeconds"),
utf16!("getTime"),
utf16!("getYear"),
utf16!("getUTCDate"),
utf16!("getUTCDay"),
utf16!("getUTCFullYear"),
utf16!("getUTCHours"),
utf16!("getUTCMinutes"),
utf16!("getUTCMonth"),
utf16!("getUTCSeconds"),
utf16!("setDate"),
utf16!("setFullYear"),
utf16!("setHours"),
utf16!("setMilliseconds"),
utf16!("setMinutes"),
utf16!("setMonth"),
utf16!("setSeconds"),
utf16!("setYear"),
utf16!("setTime"),
utf16!("setUTCDate"),
utf16!("setUTCFullYear"),
utf16!("setUTCHours"),
utf16!("setUTCMinutes"),
utf16!("setUTCMonth"),
utf16!("setUTCSeconds"),
utf16!("toDateString"),
utf16!("toGMTString"),
utf16!("toISOString"),
utf16!("toTimeString"),
utf16!("toUTCString"),
utf16!("now"),
utf16!("UTC"),
// JSON object
utf16!("JSON"),
utf16!("parse"),
utf16!("stringify"),
// Iterator object
utf16!("Array Iterator"),
utf16!("Set Iterator"),
utf16!("String Iterator"),
utf16!("Map Iterator"),
utf16!("For In Iterator"),
// Math object
utf16!("Math"),
utf16!("LN10"),
utf16!("LN2"),
utf16!("LOG10E"),
utf16!("LOG2E"),
utf16!("PI"),
utf16!("SQRT1_2"),
utf16!("SQRT2"),
utf16!("abs"),
utf16!("acos"),
utf16!("acosh"),
utf16!("asin"),
utf16!("asinh"),
utf16!("atan"),
utf16!("atanh"),
utf16!("atan2"),
utf16!("cbrt"),
utf16!("ceil"),
utf16!("clz32"),
utf16!("cos"),
utf16!("cosh"),
utf16!("exp"),
utf16!("expm1"),
utf16!("floor"),
utf16!("fround"),
utf16!("hypot"),
utf16!("imul"),
utf16!("log"),
utf16!("log1p"),
utf16!("log10"),
utf16!("log2"),
utf16!("max"),
utf16!("min"),
utf16!("pow"),
utf16!("random"),
utf16!("round"),
utf16!("sign"),
utf16!("sin"),
utf16!("sinh"),
utf16!("sqrt"),
utf16!("tan"),
utf16!("tanh"),
utf16!("trunc"),
// Intl object
utf16!("Intl"),
utf16!("DateTimeFormat"),
// TypedArray object
utf16!("TypedArray"),
utf16!("ArrayBuffer"),
utf16!("Int8Array"),
utf16!("Uint8Array"),
utf16!("Int16Array"),
utf16!("Uint16Array"),
utf16!("Int32Array"),
utf16!("Uint32Array"),
utf16!("BigInt64Array"),
utf16!("BigUint64Array"),
utf16!("Float32Array"),
utf16!("Float64Array"),
utf16!("buffer"),
utf16!("byteLength"),
utf16!("byteOffset"),
utf16!("isView"),
utf16!("subarray"),
utf16!("get byteLength"),
utf16!("get buffer"),
utf16!("get byteOffset"),
utf16!("get size"),
utf16!("get length"),
// DataView object
utf16!("DataView"),
utf16!("getBigInt64"),
utf16!("getBigUint64"),
utf16!("getFloat32"),
utf16!("getFloat64"),
utf16!("getInt8"),
utf16!("getInt16"),
utf16!("getInt32"),
utf16!("getUint8"),
utf16!("getUint16"),
utf16!("getUint32"),
utf16!("setBigInt64"),
utf16!("setBigUint64"),
utf16!("setFloat32"),
utf16!("setFloat64"),
utf16!("setInt8"),
utf16!("setInt16"),
utf16!("setInt32"),
utf16!("setUint8"),
utf16!("setUint16"),
utf16!("setUint32"),
// Console object
utf16!("console"),
utf16!("assert"),
utf16!("debug"),
utf16!("error"),
utf16!("info"),
utf16!("trace"),
utf16!("warn"),
utf16!("exception"),
utf16!("count"),
utf16!("countReset"),
utf16!("group"),
utf16!("groupCollapsed"),
utf16!("groupEnd"),
utf16!("time"),
utf16!("timeLog"),
utf16!("timeEnd"),
utf16!("dir"),
utf16!("dirxml"),
// Minified name
utf16!("a"),
utf16!("b"),
utf16!("c"),
utf16!("d"),
utf16!("e"),
utf16!("f"),
utf16!("g"),
utf16!("h"),
utf16!("i"),
utf16!("j"),
utf16!("k"),
utf16!("l"),
utf16!("m"),
utf16!("n"),
utf16!("o"),
utf16!("p"),
utf16!("q"),
utf16!("r"),
utf16!("s"),
utf16!("t"),
utf16!("u"),
utf16!("v"),
utf16!("w"),
utf16!("x"),
utf16!("y"),
utf16!("z"),
utf16!("A"),
utf16!("B"),
utf16!("C"),
utf16!("D"),
utf16!("E"),
utf16!("F"),
utf16!("G"),
utf16!("H"),
utf16!("I"),
utf16!("J"),
utf16!("K"),
utf16!("L"),
utf16!("M"),
utf16!("N"),
utf16!("O"),
utf16!("P"),
utf16!("Q"),
utf16!("R"),
utf16!("S"),
utf16!("T"),
utf16!("U"),
utf16!("V"),
utf16!("W"),
utf16!("X"),
utf16!("Y"),
utf16!("Z"),
utf16!("_"),
utf16!("$"),
// Well known symbols
utf16!("Symbol.asyncIterator"),
utf16!("[Symbol.asyncIterator]"),
utf16!("Symbol.hasInstance"),
utf16!("[Symbol.hasInstance]"),
utf16!("Symbol.isConcatSpreadable"),
utf16!("[Symbol.isConcatSpreadable]"),
utf16!("Symbol.iterator"),
utf16!("[Symbol.iterator]"),
utf16!("Symbol.match"),
utf16!("[Symbol.match]"),
utf16!("Symbol.matchAll"),
utf16!("[Symbol.matchAll]"),
utf16!("Symbol.replace"),
utf16!("[Symbol.replace]"),
utf16!("Symbol.search"),
utf16!("[Symbol.search]"),
utf16!("Symbol.species"),
utf16!("[Symbol.species]"),
utf16!("Symbol.split"),
utf16!("[Symbol.split]"),
utf16!("Symbol.toPrimitive"),
utf16!("[Symbol.toPrimitive]"),
utf16!("Symbol.toStringTag"),
utf16!("[Symbol.toStringTag]"),
utf16!("Symbol.unscopables"),
utf16!("[Symbol.unscopables]"),
];

22
boa_engine/src/string/mod.rs

@ -28,6 +28,7 @@ use crate::{
tagged::{Tagged, UnwrappedTagged},
JsBigInt,
};
use boa_builtins::{StaticString, RAW_STATICS};
use boa_gc::{empty_trace, Finalize, Trace};
pub use boa_macros::utf16;
@ -616,6 +617,27 @@ impl JsString {
ptr: Tagged::from_non_null(ptr),
}
}
pub(crate) fn as_static_string_index(&self) -> Option<u16> {
if let UnwrappedTagged::Tag(index) = self.ptr.unwrap() {
return Some(index as u16);
}
None
}
pub(crate) const unsafe fn from_index(index: u16) -> Self {
debug_assert!((index as usize) < RAW_STATICS.len());
Self {
ptr: Tagged::from_tag(index as usize),
}
}
}
impl From<StaticString> for JsString {
fn from(string: StaticString) -> Self {
Self {
ptr: Tagged::from_tag(string.index() as usize),
}
}
}
impl AsRef<[u16]> for JsString {

2
boa_engine/src/symbol.rs

@ -61,7 +61,7 @@ fn get_id() -> Option<u64> {
/// List of well known symbols.
#[derive(Debug, Clone, Copy, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
enum WellKnown {
pub(crate) enum WellKnown {
AsyncIterator,
HasInstance,
IsConcatSpreadable,

8
boa_engine/src/vm/opcode/set/property.rs

@ -94,9 +94,11 @@ impl Operation for SetPropertyByValue {
// Cannot use fast path if the [[prototype]] is a proxy object,
// because we have to the call prototypes [[set]] on non-existing property,
// and proxy objects can override [[set]].
let prototype = shape.prototype();
if prototype.map_or(false, |x| x.is_proxy()) {
break 'fast_path;
if !shape.is_static() {
let prototype = shape.prototype();
if prototype.map_or(false, |x| x.is_proxy()) {
break 'fast_path;
}
}
dense_elements.push(value.clone());

Loading…
Cancel
Save