Skip to content

Commit 7f07739

Browse files
committed
i needed to see the borrowed state of objects in the debug output, keeping for now.
Exotic objects need a specific Lazy equivalent so we can identify them in brand checks
1 parent 5d5f51d commit 7f07739

File tree

6 files changed

+259
-29
lines changed

6 files changed

+259
-29
lines changed

core/engine/src/context/intrinsics.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use boa_macros::js_str;
55

66
use crate::{
77
builtins::{
8-
function::ConstructorKind, iterable::IteratorPrototypes, uri::UriFunctions, Array, Date,
9-
IntrinsicObject, Json, Math, OrdinaryObject, RegExp, String,
8+
function::ConstructorKind, iterable::IteratorPrototypes, uri::UriFunctions, Array,
9+
IntrinsicObject, OrdinaryObject,
1010
},
1111
js_string,
1212
native_function::NativeFunctionObject,
@@ -51,7 +51,7 @@ impl Intrinsics {
5151

5252
Some(Self {
5353
constructors,
54-
objects: IntrinsicObjects::uninit(realm_inner)?,
54+
objects: IntrinsicObjects::uninit()?,
5555
templates,
5656
})
5757
}
@@ -120,7 +120,7 @@ impl StandardConstructor {
120120
/// array[0] = 42; // Sets the first element to 42
121121
/// console.log(array[0]); // Logs 42
122122
/// ```
123-
fn lazy(init: fn(&Realm) -> (), realm_inner: &WeakGc<RealmInner>) -> Self {
123+
fn lazy_array(init: fn(&Realm) -> (), realm_inner: &WeakGc<RealmInner>) -> Self {
124124
let obj: JsObject<LazyBuiltIn> = JsObject::new_unique(
125125
None,
126126
LazyBuiltIn {
@@ -136,7 +136,7 @@ impl StandardConstructor {
136136

137137
Self {
138138
constructor: constructor.clone(),
139-
prototype: JsObject::lazy_prototype(obj),
139+
prototype: JsObject::lazy_array_prototype(obj),
140140
}
141141
}
142142

@@ -264,7 +264,7 @@ impl StandardConstructors {
264264
},
265265
async_function: StandardConstructor::default(),
266266
generator_function: StandardConstructor::default(),
267-
array: StandardConstructor::lazy(Array::init, realm_inner),
267+
array: StandardConstructor::lazy_array(Array::init, realm_inner),
268268
bigint: StandardConstructor::default(),
269269
number: StandardConstructor::with_prototype(JsObject::from_proto_and_data(None, 0.0)),
270270
boolean: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
@@ -1165,7 +1165,7 @@ impl IntrinsicObjects {
11651165
///
11661166
/// [`Realm::initialize`]: crate::realm::Realm::initialize
11671167
#[allow(clippy::unnecessary_wraps)]
1168-
pub(crate) fn uninit(realm_inner: &WeakGc<RealmInner>) -> Option<Self> {
1168+
pub(crate) fn uninit() -> Option<Self> {
11691169
Some(Self {
11701170
reflect: JsObject::default(),
11711171
math: JsObject::default(),
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
use crate::{
2+
object::{
3+
internal_methods::{
4+
non_existant_call, non_existant_construct, ordinary_define_own_property,
5+
ordinary_delete, ordinary_get, ordinary_get_own_property, ordinary_get_prototype_of,
6+
ordinary_has_property, ordinary_is_extensible, ordinary_own_property_keys,
7+
ordinary_prevent_extensions, ordinary_set, ordinary_set_prototype_of, ordinary_try_get,
8+
InternalMethodContext, InternalObjectMethods,
9+
},
10+
JsPrototype,
11+
},
12+
property::{PropertyDescriptor, PropertyKey},
13+
Context, JsData, JsObject, JsResult, JsValue,
14+
};
15+
use boa_gc::{Finalize, Trace};
16+
17+
use super::LazyBuiltIn;
18+
19+
/// The `LazyArrayPrototype` struct is responsible for ensuring that the prototype
20+
/// of a constructor is lazily initialized. In JavaScript, constructors have a
21+
/// `prototype` property that points to an object which is used as the prototype
22+
/// for instances created by that constructor.
23+
///
24+
/// The `LazyArrayPrototype` struct is used within `JsObject` (e.g., `JsObject<LazyPrototype>`)
25+
/// to defer the creation of the prototype object until it is actually needed.
26+
/// This lazy initialization helps improve performance by avoiding the creation
27+
/// of the prototype object until it is necessary.
28+
///
29+
/// Each `LazyArrayPrototype` instance points to the constructor's `lazyBuiltin` (via its
30+
/// object) and triggers the initialization of the prototype if any methods on
31+
/// the prototype are called.
32+
33+
#[derive(Clone, Trace, Finalize, Debug)]
34+
#[allow(clippy::type_complexity)]
35+
pub struct LazyArrayPrototype {
36+
pub(crate) constructor: JsObject<LazyBuiltIn>,
37+
}
38+
39+
// Implement the trait for JsData by overriding all internal_methods by calling init on the LazyBuiltIn associated with this prototype
40+
impl JsData for LazyArrayPrototype {
41+
fn internal_methods(&self) -> &'static InternalObjectMethods {
42+
&LAZY_INTERNAL_METHODS
43+
}
44+
}
45+
46+
pub(crate) static LAZY_INTERNAL_METHODS: InternalObjectMethods = InternalObjectMethods {
47+
__get_prototype_of__: lazy_get_prototype_of,
48+
__set_prototype_of__: lazy_set_prototype_of,
49+
__is_extensible__: lazy_is_extensible,
50+
__prevent_extensions__: lazy_prevent_extensions,
51+
__get_own_property__: lazy_get_own_property,
52+
__define_own_property__: lazy_define_own_property,
53+
__has_property__: lazy_has_property,
54+
__try_get__: lazy_try_get,
55+
__get__: lazy_get,
56+
__set__: lazy_set,
57+
__delete__: lazy_delete,
58+
__own_property_keys__: lazy_own_property_keys,
59+
__call__: non_existant_call,
60+
__construct__: non_existant_construct,
61+
};
62+
63+
pub(crate) fn lazy_get_prototype_of(
64+
obj: &JsObject,
65+
context: &mut Context,
66+
) -> JsResult<JsPrototype> {
67+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
68+
.clone()
69+
.downcast::<LazyArrayPrototype>()
70+
.expect("obj is not a Builtin");
71+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
72+
LazyBuiltIn::ensure_init(lazy_built_in);
73+
ordinary_get_prototype_of(obj, context)
74+
}
75+
76+
pub(crate) fn lazy_set_prototype_of(
77+
obj: &JsObject,
78+
prototype: JsPrototype,
79+
context: &mut Context,
80+
) -> JsResult<bool> {
81+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
82+
.clone()
83+
.downcast::<LazyArrayPrototype>()
84+
.expect("obj is not a Builtin");
85+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
86+
LazyBuiltIn::ensure_init(lazy_built_in);
87+
ordinary_set_prototype_of(obj, prototype, context)
88+
}
89+
pub(crate) fn lazy_is_extensible(obj: &JsObject, context: &mut Context) -> JsResult<bool> {
90+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
91+
.clone()
92+
.downcast::<LazyArrayPrototype>()
93+
.expect("obj is not a Builtin");
94+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
95+
LazyBuiltIn::ensure_init(lazy_built_in);
96+
ordinary_is_extensible(obj, context)
97+
}
98+
99+
pub(crate) fn lazy_prevent_extensions(obj: &JsObject, context: &mut Context) -> JsResult<bool> {
100+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
101+
.clone()
102+
.downcast::<LazyArrayPrototype>()
103+
.expect("obj is not a Builtin");
104+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
105+
LazyBuiltIn::ensure_init(lazy_built_in);
106+
ordinary_prevent_extensions(obj, context)
107+
}
108+
109+
pub(crate) fn lazy_get_own_property(
110+
obj: &JsObject,
111+
key: &PropertyKey,
112+
context: &mut InternalMethodContext<'_>,
113+
) -> JsResult<Option<PropertyDescriptor>> {
114+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
115+
.clone()
116+
.downcast::<LazyArrayPrototype>()
117+
.expect("obj is not a Builtin");
118+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
119+
LazyBuiltIn::ensure_init(lazy_built_in);
120+
ordinary_get_own_property(obj, key, context)
121+
}
122+
123+
pub(crate) fn lazy_define_own_property(
124+
obj: &JsObject,
125+
key: &PropertyKey,
126+
desc: PropertyDescriptor,
127+
context: &mut InternalMethodContext<'_>,
128+
) -> JsResult<bool> {
129+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
130+
.clone()
131+
.downcast::<LazyArrayPrototype>()
132+
.expect("obj is not a Builtin");
133+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
134+
LazyBuiltIn::ensure_init(lazy_built_in);
135+
136+
ordinary_define_own_property(obj, key, desc, context)
137+
}
138+
139+
pub(crate) fn lazy_has_property(
140+
obj: &JsObject,
141+
key: &PropertyKey,
142+
context: &mut InternalMethodContext<'_>,
143+
) -> JsResult<bool> {
144+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
145+
.clone()
146+
.downcast::<LazyArrayPrototype>()
147+
.expect("obj is not a Builtin");
148+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
149+
LazyBuiltIn::ensure_init(lazy_built_in);
150+
ordinary_has_property(obj, key, context)
151+
}
152+
153+
pub(crate) fn lazy_try_get(
154+
obj: &JsObject,
155+
key: &PropertyKey,
156+
receiver: JsValue,
157+
context: &mut InternalMethodContext<'_>,
158+
) -> JsResult<Option<JsValue>> {
159+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
160+
.clone()
161+
.downcast::<LazyArrayPrototype>()
162+
.expect("obj is not a Builtin");
163+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
164+
LazyBuiltIn::ensure_init(lazy_built_in);
165+
166+
ordinary_try_get(obj, key, receiver, context)
167+
}
168+
169+
pub(crate) fn lazy_get(
170+
obj: &JsObject,
171+
key: &PropertyKey,
172+
receiver: JsValue,
173+
context: &mut InternalMethodContext<'_>,
174+
) -> JsResult<JsValue> {
175+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
176+
.clone()
177+
.downcast::<LazyArrayPrototype>()
178+
.expect("obj is not a Builtin");
179+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
180+
LazyBuiltIn::ensure_init(lazy_built_in);
181+
ordinary_get(obj, key, receiver, context)
182+
}
183+
184+
pub(crate) fn lazy_set(
185+
obj: &JsObject,
186+
key: PropertyKey,
187+
value: JsValue,
188+
receiver: JsValue,
189+
context: &mut InternalMethodContext<'_>,
190+
) -> JsResult<bool> {
191+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
192+
.clone()
193+
.downcast::<LazyArrayPrototype>()
194+
.expect("obj is not a Builtin");
195+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
196+
LazyBuiltIn::ensure_init(lazy_built_in);
197+
ordinary_set(obj, key, value, receiver, context)
198+
}
199+
200+
pub(crate) fn lazy_delete(
201+
obj: &JsObject,
202+
key: &PropertyKey,
203+
context: &mut InternalMethodContext<'_>,
204+
) -> JsResult<bool> {
205+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
206+
.clone()
207+
.downcast::<LazyArrayPrototype>()
208+
.expect("obj is not a Builtin");
209+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
210+
LazyBuiltIn::ensure_init(lazy_built_in);
211+
ordinary_delete(obj, key, context)
212+
}
213+
214+
pub(crate) fn lazy_own_property_keys(
215+
obj: &JsObject,
216+
context: &mut Context,
217+
) -> JsResult<Vec<PropertyKey>> {
218+
let lazy_prototype: JsObject<LazyArrayPrototype> = obj
219+
.clone()
220+
.downcast::<LazyArrayPrototype>()
221+
.expect("obj is not a Builtin");
222+
let lazy_built_in = &lazy_prototype.borrow_mut().data.constructor.clone();
223+
LazyBuiltIn::ensure_init(lazy_built_in);
224+
225+
ordinary_own_property_keys(obj, context)
226+
}

core/engine/src/object/builtins/lazy_builtin.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use boa_gc::{Finalize, Trace, WeakGc};
2323
#[derive(Debug, Clone, Trace, Finalize)]
2424
pub(crate) enum BuiltinKind {
2525
Function(NativeFunctionObject),
26+
#[allow(dead_code)]
2627
Ordinary,
2728
}
2829

core/engine/src/object/builtins/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod jsset;
1717
mod jsset_iterator;
1818
mod jssharedarraybuffer;
1919
mod jstypedarray;
20+
mod lazy_array_prototype;
2021
mod lazy_builtin;
2122
mod lazy_prototype;
2223

@@ -35,5 +36,6 @@ pub use jsset::*;
3536
pub use jsset_iterator::*;
3637
pub use jssharedarraybuffer::*;
3738
pub use jstypedarray::*;
39+
pub use lazy_array_prototype::*;
3840
pub use lazy_builtin::*;
3941
pub use lazy_prototype::*;

core/engine/src/object/jsobject.rs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
use super::{
66
internal_methods::{InternalMethodContext, InternalObjectMethods, ORDINARY_INTERNAL_METHODS},
77
shape::RootShape,
8-
BuiltinKind, JsPrototype, LazyBuiltIn, LazyPrototype, NativeObject, Object, PrivateName,
9-
PropertyMap,
8+
JsPrototype, LazyArrayPrototype, LazyBuiltIn, NativeObject, Object, PrivateName, PropertyMap,
109
};
1110
use crate::{
1211
builtins::{
@@ -18,11 +17,10 @@ use crate::{
1817
error::JsNativeError,
1918
js_string,
2019
property::{PropertyDescriptor, PropertyKey},
21-
realm::{Realm, RealmInner},
2220
value::PreferredType,
2321
Context, JsResult, JsString, JsValue,
2422
};
25-
use boa_gc::{self, Finalize, Gc, GcBox, GcRefCell, Trace, WeakGc};
23+
use boa_gc::{self, Finalize, Gc, GcBox, GcRefCell, Trace};
2624
use boa_macros::js_str;
2725
use std::{
2826
cell::RefCell,
@@ -95,21 +93,10 @@ impl JsObject {
9593
}
9694
}
9795

98-
/// Creates a new lazy `JsObject` from its inner object and its vtable.
99-
/// This object will call `init(realm)` when it's first accessed
100-
pub(crate) fn lazy(init: fn(&Realm) -> (), realm_inner: &WeakGc<RealmInner>) -> Self {
101-
let data = LazyBuiltIn {
102-
init_and_realm: Some((init, realm_inner.clone())),
103-
kind: BuiltinKind::Ordinary,
104-
};
105-
106-
Self::from_proto_and_data(None, data)
107-
}
108-
109-
/// Creates a new lazy `JsObject` from its inner object and its vtable.
96+
/// Creates a new lazy array prototype object from its inner object and its vtable.
11097
/// This is used for built-in objects that are prototypes of Constructors.
111-
pub(crate) fn lazy_prototype(constructor: JsObject<LazyBuiltIn>) -> Self {
112-
Self::from_proto_and_data(None, LazyPrototype { constructor })
98+
pub(crate) fn lazy_array_prototype(constructor: JsObject<LazyBuiltIn>) -> Self {
99+
Self::from_proto_and_data(None, LazyArrayPrototype { constructor })
113100
}
114101

115102
/// Creates a new ordinary object with its prototype set to the `Object` prototype.
@@ -300,6 +287,12 @@ impl JsObject {
300287
#[must_use]
301288
#[track_caller]
302289
pub fn is_array(&self) -> bool {
290+
// The prototype of an array should be an exotic Array object.
291+
// If its the lazyArrayPrototype we know its an array.
292+
if self.is::<LazyArrayPrototype>() {
293+
return true;
294+
}
295+
303296
std::ptr::eq(self.vtable(), &ARRAY_EXOTIC_INTERNAL_METHODS)
304297
}
305298

@@ -948,6 +941,7 @@ impl<T: NativeObject + ?Sized> Debug for JsObject<T> {
948941
if !limiter.visited && !limiter.live {
949942
let ptr: *const _ = self.as_ref();
950943
let ptr = ptr.cast::<()>();
944+
let borrow_flag = self.inner.object.flags.get();
951945
let obj = self.borrow();
952946
let kind = obj.data.type_name_of_value();
953947
if self.is_callable() {
@@ -963,10 +957,16 @@ impl<T: NativeObject + ?Sized> Debug for JsObject<T> {
963957
.unwrap_or_default(),
964958
};
965959

966-
return f.write_fmt(format_args!("({:?}) {:?} 0x{:X}", kind, name, ptr as usize));
960+
return f.write_fmt(format_args!(
961+
"({:?}) {:?} 0x{:X} {:?}",
962+
kind, name, ptr as usize, borrow_flag
963+
));
967964
}
968965

969-
f.write_fmt(format_args!("({:?}) 0x{:X}", kind, ptr as usize))
966+
f.write_fmt(format_args!(
967+
"({:?}) 0x{:X} {:?}",
968+
kind, ptr as usize, borrow_flag
969+
))
970970
} else {
971971
f.write_str("{ ... }")
972972
}

0 commit comments

Comments
 (0)