Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement static shapes
Browse files Browse the repository at this point in the history
HalidOdat committed Apr 24, 2023
1 parent bd062f8 commit 20da877
Showing 17 changed files with 559 additions and 18 deletions.
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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" }
21 changes: 21 additions & 0 deletions boa_builtins/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[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"

[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"
1 change: 1 addition & 0 deletions boa_builtins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TOOD
192 changes: 192 additions & 0 deletions boa_builtins/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
use std::fs::File;
use std::hash::{Hash, Hasher};
use std::io::{self, BufWriter, Write};
use std::path::Path;
use std::{env, fmt};

use phf_shared::{FmtConst, PhfBorrow, PhfHash};

use boa_macros::utf16;

/// List of well known symbols.
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
#[allow(dead_code)]
enum WellKnown {
AsyncIterator,
HasInstance,
IsConcatSpreadable,
Iterator,
Match,
MatchAll,
Replace,
Search,
Species,
Split,
ToPrimitive,
ToStringTag,
Unscopables,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum StaticPropertyKey<'a> {
String(&'a [u16]),
Symbol(u8),
}

impl PhfHash for StaticPropertyKey<'static> {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
self.hash(state)
}
}

impl FmtConst for StaticPropertyKey<'static> {
fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if matches!(self, StaticPropertyKey::String(_)) {
f.write_str("StaticPropertyKey::String(")?;
} else {
f.write_str("StaticPropertyKey::Symbol(")?;
}

match self {
StaticPropertyKey::String(s) => write!(f, "&{:?})", s),
StaticPropertyKey::Symbol(s) => write!(f, "{})", s),
}
}
}

impl<'b, 'a: 'b> PhfBorrow<StaticPropertyKey<'b>> for StaticPropertyKey<'a> {
fn borrow(&self) -> &StaticPropertyKey<'b> {
self
}
}

fn main() -> io::Result<()> {
let file = Path::new(&env::var("OUT_DIR").unwrap()).join("static_shapes_codegen.rs");
let mut file = BufWriter::new(File::create(file)?);

// writeln!(&mut file, "\n\n")?;

writeln!(
&mut file,
"pub static EMPTY_OBJECT_STATIC_SHAPE: ::phf::OrderedMap::<StaticPropertyKey<'static>, (u32, Attribute)> = \n{};",
phf_codegen::OrderedMap::<StaticPropertyKey<'static>>::new()
.build()
)?;

writeln!(
&mut file,
"pub static JSON_OBJECT_STATIC_SHAPE: ::phf::OrderedMap::<StaticPropertyKey<'static>, (u32, Attribute)> = \n{};",
phf_codegen::OrderedMap::new()
.entry(StaticPropertyKey::String(utf16!("parse")), "(0, Attribute::WRITABLE.union(Attribute::CONFIGURABLE))")
.entry(StaticPropertyKey::String(utf16!("stringify")), "(1, Attribute::WRITABLE.union(Attribute::CONFIGURABLE))")
.entry(StaticPropertyKey::Symbol(WellKnown::ToStringTag as u8), "(2, Attribute::WRITABLE.union(Attribute::CONFIGURABLE))")
.build()
)?;

// writeln!(
// &mut file,
// "static BYTE_STR_KEYS: ::phf::Map<&[u8], u32> = \n{};",
// phf_codegen::Map::<&[u8]>::new()
// .entry(b"foo", "0")
// .entry(b"bar", "1")
// .entry(b"baz", "2")
// .entry(b"quux4555", "3")
// .build()
// )?;

// writeln!(
// &mut file,
// "static SET: ::phf::Set<u32> = \n{};",
// phf_codegen::Set::new()
// .entry(1u32)
// .entry(2u32)
// .entry(3u32)
// .build()
// )?;

// writeln!(
// &mut file,
// "static ORDERED_MAP: ::phf::OrderedMap<u32, &'static str> = \n{};",
// phf_codegen::OrderedMap::new()
// .entry(1u32, "\"a\"")
// .entry(2u32, "\"b\"")
// .entry(3u32, "\"c\"")
// .build()
// )?;

// writeln!(
// &mut file,
// "static ORDERED_SET: ::phf::OrderedSet<u32> = \n{};",
// phf_codegen::OrderedSet::new()
// .entry(1u32)
// .entry(2u32)
// .entry(3u32)
// .build()
// )?;

// writeln!(
// &mut file,
// "static STR_KEYS: ::phf::Map<&'static str, u32> = \n{};",
// phf_codegen::Map::new()
// .entry("a", "1")
// .entry("b", "2")
// .entry("c", "3")
// .build()
// )?;

// write!(
// &mut file,
// "static UNICASE_MAP: ::phf::Map<::unicase::UniCase<&'static str>, &'static str> = \n{};",
// phf_codegen::Map::new()
// .entry(UniCase::new("abc"), "\"a\"")
// .entry(UniCase::new("DEF"), "\"b\"")
// .build()
// )?;

// write!(
// &mut file,
// "static UNCASED_MAP: ::phf::Map<&'static ::uncased::UncasedStr, &'static str> = \n{};",
// phf_codegen::Map::new()
// .entry(UncasedStr::new("abc"), "\"a\"")
// .entry(UncasedStr::new("DEF"), "\"b\"")
// .build()
// )?;

// //u32 is used here purely for a type that impls `Hash+PhfHash+Eq+fmt::Debug`, but is not required for the empty test itself
// writeln!(
// &mut file,
// "static EMPTY: ::phf::Map<u32, u32> = \n{};",
// phf_codegen::Map::<u32>::new().build()
// )?;

// writeln!(
// &mut file,
// "static EMPTY_ORDERED: ::phf::OrderedMap<u32, u32> = \n{};",
// phf_codegen::OrderedMap::<u32>::new().build()
// )?;

// writeln!(
// &mut file,
// "static ARRAY_KEYS: ::phf::Map<[u8; 3], u32> = \n{};",
// phf_codegen::Map::<[u8; 3]>::new()
// .entry(*b"foo", "0")
// .entry(*b"bar", "1")
// .entry(*b"baz", "2")
// .build()
// )?;

// // key type required here as it will infer `&'static [u8; 3]` instead
// writeln!(
// &mut file,
// "static BYTE_STR_KEYS: ::phf::Map<&[u8], u32> = \n{};",
// phf_codegen::Map::<&[u8]>::new()
// .entry(b"foo", "0")
// .entry(b"bar", "1")
// .entry(b"baz", "2")
// .entry(b"quux", "3")
// .build()
// )
Ok(())
}
47 changes: 47 additions & 0 deletions boa_builtins/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::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(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StaticPropertyKey<'a> {
String(&'a [u16]),
Symbol(u8),
}

impl PhfHash for StaticPropertyKey<'static> {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
self.hash(state)
}
}

impl<'b, 'a: 'b> PhfBorrow<StaticPropertyKey<'b>> for StaticPropertyKey<'a> {
#[inline]
fn borrow(&self) -> &StaticPropertyKey<'b> {
self
}
}

pub type Slot = (u32, Attribute);
pub type StaticShape = phf::OrderedMap<StaticPropertyKey<'static>, Slot>;

include!(concat!(env!("OUT_DIR"), "/static_shapes_codegen.rs"));

// static NUMBER_BUITIN_OBJECT_STATIC_SHAPE_REF: &StaticShape = &NUMBER_BUITIN_OBJECT_STATIC_SHAPE;
6 changes: 5 additions & 1 deletion boa_cli/src/debug/shape.rs
Original file line number Diff line number Diff line change
@@ -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())
}
1 change: 1 addition & 0 deletions boa_engine/Cargo.toml
Original file line number Diff line number Diff line change
@@ -47,6 +47,7 @@ annex-b = ["boa_parser/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
19 changes: 9 additions & 10 deletions boa_engine/src/builtins/json/mod.rs
Original file line number Diff line number Diff line change
@@ -24,10 +24,9 @@ use crate::{
error::JsNativeError,
js_string,
object::{JsObject, RecursionLimiter},
property::{Attribute, PropertyNameKind},
property::PropertyNameKind,
realm::Realm,
string::{utf16, CodePoint},
symbol::JsSymbol,
value::IntegerOrInfinity,
Context, JsArgs, JsResult, JsString, JsValue,
};
@@ -49,14 +48,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, js_string!("parse"), 2)
.static_method(Self::stringify, js_string!("stringify"), 3)
.static_property(Self::NAME)
.build();
}

fn get(intrinsics: &Intrinsics) -> JsObject {
68 changes: 67 additions & 1 deletion boa_engine/src/builtins/mod.rs
Original file line number Diff line number Diff line change
@@ -95,7 +95,10 @@ use crate::{
js_string,
native_function::{NativeFunction, NativeFunctionPointer},
object::{
shape::{property_table::PropertyTableInner, slot::SlotAttributes},
shape::{
property_table::PropertyTableInner, slot::SlotAttributes, static_shape::StaticShape,
Shape,
},
FunctionBinding, JsFunction, JsObject, JsPrototype, Object, ObjectData, ObjectKind,
CONSTRUCTOR, PROTOTYPE,
},
@@ -584,6 +587,56 @@ struct BuiltInBuilder<'ctx, Kind> {
prototype: JsObject,
}

struct BuiltInBuilderStaticShape<'ctx> {
realm: &'ctx Realm,
shape: &'static boa_builtins::StaticShape,
object: JsObject,
storage: Vec<JsValue>,
}

impl BuiltInBuilderStaticShape<'_> {
/// Adds a new static method to the builtin object.
fn static_method(
mut self,
function: NativeFunctionPointer,
name: JsString,
length: usize,
) -> Self {
let function = BuiltInBuilder::callable(self.realm, function)
.name(name)
.length(length)
.build();

self.storage.push(function.into());
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
}

fn build(mut self) {
debug_assert_eq!(self.storage.len(), self.shape.len());

let mut object = self.object.borrow_mut();
object.properties_mut().shape = Shape::r#static(StaticShape::new(self.shape));
self.storage.push(
self.realm
.intrinsics()
.constructors()
.object()
.prototype()
.into(),
);
object.properties_mut().storage = self.storage;
}
}

impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> {
// fn new(realm: &'ctx Realm) -> BuiltInBuilder<'ctx, OrdinaryObject> {
// BuiltInBuilder {
@@ -607,6 +660,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.len() + 1),
// prototype: realm.intrinsics().constructors().object().prototype(),
}
}
}

struct BuiltInConstructorWithPrototype<'ctx> {
2 changes: 1 addition & 1 deletion boa_engine/src/context/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -816,7 +816,7 @@ impl Default for IntrinsicObjects {
Self {
reflect: JsObject::default(),
math: JsObject::default(),
json: JsObject::default(),
json: JsObject::default_with_static_shape(),
throw_type_error: JsFunction::empty_intrinsic_function(false),
array_prototype_values: JsFunction::empty_intrinsic_function(false),
iterator_prototypes: IteratorPrototypes::default(),
6 changes: 6 additions & 0 deletions boa_engine/src/object/jsobject.rs
Original file line number Diff line number Diff line change
@@ -59,6 +59,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,
20 changes: 19 additions & 1 deletion boa_engine/src/object/mod.rs
Original file line number Diff line number Diff line change
@@ -24,7 +24,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::{
@@ -838,6 +838,18 @@ impl Debug for ObjectKind {
}

impl Object {
fn with_empty_shape() -> Self {
Self {
kind: ObjectKind::Ordinary,
properties: PropertyMap::new(
Shape::r#static(StaticShape::new(&boa_builtins::EMPTY_OBJECT_STATIC_SHAPE)),
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
@@ -1489,6 +1501,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()
}

27 changes: 25 additions & 2 deletions boa_engine/src/object/shape/mod.rs
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
pub(crate) mod property_table;
pub(crate) mod shared_shape;
pub(crate) mod slot;
pub(crate) mod static_shape;
pub(crate) mod unique_shape;

pub use shared_shape::SharedShape;
@@ -14,7 +15,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;

@@ -54,6 +55,7 @@ pub(crate) struct ChangeTransition<T> {
enum Inner {
Unique(UniqueShape),
Shared(SharedShape),
Static(StaticShape),
}

/// Represents the shape of an object.
@@ -89,6 +91,13 @@ impl Shape {
}
}

/// Create a [`Shape`] from a [`StaticShape`].
pub(crate) const fn r#static(shape: StaticShape) -> Self {
Self {
inner: Inner::Static(shape),
}
}

/// Returns `true` if it's a shared shape, `false` otherwise.
#[inline]
pub const fn is_shared(&self) -> bool {
@@ -101,6 +110,12 @@ impl Shape {
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);
@@ -121,6 +136,7 @@ impl Shape {
Self::shared(shape)
}
Inner::Unique(shape) => Self::unique(shape.insert_property_transition(key)),
Inner::Static(shape) => Self::unique(shape.insert_property_transition(key)),
}
}

@@ -147,6 +163,7 @@ impl Shape {
}
}
Inner::Unique(shape) => shape.change_attributes_transition(&key),
Inner::Static(shape) => shape.change_attributes_transition(&key),
}
}

@@ -163,6 +180,7 @@ impl Shape {
Self::shared(shape)
}
Inner::Unique(shape) => Self::unique(shape.remove_property_transition(key)),
Inner::Static(shape) => Self::unique(shape.remove_property_transition(key)),
}
}

@@ -177,14 +195,16 @@ impl Shape {
Self::shared(shape)
}
Inner::Unique(shape) => Self::unique(shape.change_prototype_transition(prototype)),
Inner::Static(shape) => Self::unique(shape.change_prototype_transition(prototype)),
}
}

/// 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"),
}
}

@@ -194,6 +214,7 @@ impl Shape {
match &self.inner {
Inner::Shared(shape) => shape.lookup(key),
Inner::Unique(shape) => shape.lookup(key),
Inner::Static(shape) => shape.lookup(key),
}
}

@@ -203,6 +224,7 @@ impl Shape {
match &self.inner {
Inner::Shared(shape) => shape.keys(),
Inner::Unique(shape) => shape.keys(),
Inner::Static(shape) => shape.keys(),
}
}

@@ -212,6 +234,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(),
}
}
}
2 changes: 1 addition & 1 deletion boa_engine/src/object/shape/slot.rs
Original file line number Diff line number Diff line change
@@ -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,
139 changes: 139 additions & 0 deletions boa_engine/src/object/shape/static_shape.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Temp allow
#![allow(dead_code)]
#![allow(clippy::needless_pass_by_value)]

use std::fmt::Debug;

use boa_builtins::StaticPropertyKey;
use boa_gc::{Finalize, Trace};

use crate::{property::PropertyKey, symbol::WellKnown, 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(s) => PropertyKey::from(*s),
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_slice())),
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)?;

// SAFETY: only used to extend the lifetime, so we are able to call get.
let key: &StaticPropertyKey<'static> = unsafe { std::mem::transmute(&key) };
let (index, attributes) = self.inner.get(key)?;

Some(Slot {
index: *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.keys().map(from_static_property_key).collect()
}

/// TODO: doc
pub(crate) fn to_unique(&self, _prototype: JsPrototype) -> UniqueShape {
// UniqueShape::new(
// prototype,
// self.property_table()
// .inner()
// .borrow()
// .clone_count(self.property_count()),
// )
todo!()
}

/// Return location in memory of the [`UniqueShape`].
pub(crate) fn to_addr_usize(&self) -> usize {
let ptr: *const _ = self.inner;
ptr as usize
}
}
2 changes: 1 addition & 1 deletion boa_engine/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -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,

0 comments on commit 20da877

Please sign in to comment.