Skip to content

Commit 4d63273

Browse files
committed
good working state
1 parent 56fa816 commit 4d63273

File tree

6 files changed

+124
-116
lines changed

6 files changed

+124
-116
lines changed

.vscode/tasks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"type": "process",
3838
"label": "Run JS file",
3939
"command": "cargo",
40-
"args": ["run", "--bin", "boa", "${file}"],
40+
"args": ["run", "--bin", "boa", "${workspaceFolder}/debug/script.js"],
4141
"group": {
4242
"kind": "build",
4343
"isDefault": true

core/engine/src/context/intrinsics.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use boa_macros::js_str;
66
use crate::{
77
builtins::{
88
function::ConstructorKind, iterable::IteratorPrototypes, uri::UriFunctions, Array, Date,
9-
IntrinsicObject, Math, OrdinaryObject,
9+
IntrinsicObject, OrdinaryObject,
1010
},
1111
js_string,
1212
native_function::NativeFunctionObject,
@@ -100,9 +100,28 @@ impl StandardConstructor {
100100
}
101101
}
102102

103-
/// Similar to `with_prototype`, but the prototype is lazily initialized.
103+
/// Build a constructor that is lazily initialized.
104+
/// Both the constructor and the prototype are lazily initialized.
105+
///
106+
/// For example: Both the initiation of the `Array` and accessing its prototype will fire `init` once.
107+
/// This means that the actual creation of the array and the retrieval of its
108+
/// prototype are deferred until they are actually needed.
109+
///
110+
/// ## Example
111+
///
112+
/// ```javascript
113+
/// // Lazy initiation of the Array
114+
/// let array = new Array(10); // Creates an array with 10 empty slots
115+
///
116+
/// // Lazy access to the prototype
117+
/// let prototype = Object.getPrototypeOf(array);
118+
///
119+
/// // Accessing an index in the array
120+
/// array[0] = 42; // Sets the first element to 42
121+
/// console.log(array[0]); // Logs 42
122+
/// ```
104123
fn lazy(init: fn(&Realm) -> (), realm_inner: &WeakGc<RealmInner>) -> Self {
105-
let obj = JsObject::from_proto_and_data(
124+
let obj: JsObject<LazyBuiltIn> = JsObject::new_unique(
106125
None,
107126
LazyBuiltIn {
108127
init_and_realm: Some((init, realm_inner.clone())),
@@ -113,11 +132,11 @@ impl StandardConstructor {
113132
}),
114133
},
115134
);
116-
let constructor = JsFunction::from_object_unchecked(obj);
135+
let constructor = JsFunction::from_object_unchecked(obj.clone().upcast());
117136

118137
Self {
119138
constructor: constructor.clone(),
120-
prototype: JsObject::lazy_prototype(obj.clone()),
139+
prototype: JsObject::lazy_prototype(obj),
121140
}
122141
}
123142

@@ -245,7 +264,7 @@ impl StandardConstructors {
245264
},
246265
async_function: StandardConstructor::default(),
247266
generator_function: StandardConstructor::default(),
248-
array: StandardConstructor::lazy(Array::init, &realm_inner),
267+
array: StandardConstructor::lazy(Array::init, realm_inner),
249268
bigint: StandardConstructor::default(),
250269
number: StandardConstructor::with_prototype(JsObject::from_proto_and_data(None, 0.0)),
251270
boolean: StandardConstructor::with_prototype(JsObject::from_proto_and_data(

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

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
//! A Rust API wrapper for Boa's `Function` Builtin ECMAScript Object
2-
use crate::realm::{Realm, RealmInner};
32
use crate::{
43
builtins::function::ConstructorKind, native_function::NativeFunctionObject, object::JsObject,
54
value::TryFromJs, Context, JsNativeError, JsResult, JsValue, NativeFunction, TryIntoJsResult,
65
};
7-
use boa_gc::{Finalize, Trace, WeakGc};
6+
use boa_gc::{Finalize, Trace};
87
use std::marker::PhantomData;
98
use std::ops::Deref;
109

11-
use super::lazy_builtin::{BuiltinKind, LazyBuiltIn};
12-
1310
/// A trait for converting a tuple of Rust values into a vector of `JsValue`,
1411
/// to be used as arguments for a JavaScript function.
1512
pub trait TryIntoJsArguments {
@@ -138,28 +135,6 @@ impl JsFunction {
138135
}
139136
}
140137

141-
/// Creates a new, lazy intrinsic functionobject with only its function internal methods set.
142-
/// When the function is accessed it will call init from the procided init function
143-
pub(crate) fn lazy_intrinsic_function(
144-
constructor: bool,
145-
init: fn(&Realm),
146-
realm_inner: WeakGc<RealmInner>,
147-
) -> Self {
148-
Self {
149-
inner: JsObject::from_proto_and_data(
150-
None,
151-
LazyBuiltIn {
152-
init_and_realm: Some((init, realm_inner)),
153-
kind: BuiltinKind::Function(NativeFunctionObject {
154-
f: NativeFunction::from_fn_ptr(|_, _, _| Ok(JsValue::undefined())),
155-
constructor: constructor.then_some(ConstructorKind::Base),
156-
realm: None,
157-
}),
158-
},
159-
),
160-
}
161-
}
162-
163138
/// Creates a [`JsFunction`] from a [`JsObject`], or returns `None` if the object is not a function.
164139
///
165140
/// This does not clone the fields of the function, it only does a shallow clone of the object.

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

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ pub(crate) enum BuiltinKind {
2424
Ordinary,
2525
}
2626

27-
/// A builtin function. Used for lazy initialization of builtins.
28-
27+
/// A Lazy Built-in data structure. Used for lazy initialization of builtins.
2928
#[derive(Clone, Finalize, Debug)]
3029
#[allow(clippy::type_complexity)]
3130
pub struct LazyBuiltIn {
@@ -44,8 +43,9 @@ impl LazyBuiltIn {
4443
}
4544
}
4645

47-
pub(crate) fn ensure_init(mut built_in: Self) {
48-
if let Some((init, realm_inner)) = built_in.init_and_realm.take() {
46+
pub(crate) fn ensure_init(built_in: &JsObject<LazyBuiltIn>) {
47+
let borrowed_built_in = built_in.borrow_mut().data.init_and_realm.take();
48+
if let Some((init, realm_inner)) = borrowed_built_in {
4949
let realm = &Realm {
5050
inner: realm_inner.upgrade().expect("realm_inner not set"),
5151
};
@@ -100,7 +100,7 @@ pub(crate) fn lazy_get_prototype_of(
100100
context: &mut Context,
101101
) -> JsResult<JsPrototype> {
102102
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
103-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
103+
LazyBuiltIn::ensure_init(&builtin);
104104
ordinary_get_prototype_of(obj, context)
105105
}
106106

@@ -110,18 +110,18 @@ pub(crate) fn lazy_set_prototype_of(
110110
context: &mut Context,
111111
) -> JsResult<bool> {
112112
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
113-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
113+
LazyBuiltIn::ensure_init(&builtin);
114114
ordinary_set_prototype_of(obj, prototype, context)
115115
}
116116
pub(crate) fn lazy_is_extensible(obj: &JsObject, context: &mut Context) -> JsResult<bool> {
117117
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
118-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
118+
LazyBuiltIn::ensure_init(&builtin);
119119
ordinary_is_extensible(obj, context)
120120
}
121121

122122
pub(crate) fn lazy_prevent_extensions(obj: &JsObject, context: &mut Context) -> JsResult<bool> {
123123
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
124-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
124+
LazyBuiltIn::ensure_init(&builtin);
125125
ordinary_prevent_extensions(obj, context)
126126
}
127127

@@ -131,7 +131,7 @@ pub(crate) fn lazy_get_own_property(
131131
context: &mut InternalMethodContext<'_>,
132132
) -> JsResult<Option<PropertyDescriptor>> {
133133
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
134-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
134+
LazyBuiltIn::ensure_init(&builtin);
135135
ordinary_get_own_property(obj, key, context)
136136
}
137137

@@ -142,7 +142,7 @@ pub(crate) fn lazy_define_own_property(
142142
context: &mut InternalMethodContext<'_>,
143143
) -> JsResult<bool> {
144144
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
145-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
145+
LazyBuiltIn::ensure_init(&builtin);
146146

147147
ordinary_define_own_property(obj, key, desc, context)
148148
}
@@ -153,7 +153,7 @@ pub(crate) fn lazy_has_property(
153153
context: &mut InternalMethodContext<'_>,
154154
) -> JsResult<bool> {
155155
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
156-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
156+
LazyBuiltIn::ensure_init(&builtin);
157157
ordinary_has_property(obj, key, context)
158158
}
159159

@@ -164,7 +164,7 @@ pub(crate) fn lazy_try_get(
164164
context: &mut InternalMethodContext<'_>,
165165
) -> JsResult<Option<JsValue>> {
166166
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
167-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
167+
LazyBuiltIn::ensure_init(&builtin);
168168

169169
ordinary_try_get(obj, key, receiver, context)
170170
}
@@ -176,7 +176,7 @@ pub(crate) fn lazy_get(
176176
context: &mut InternalMethodContext<'_>,
177177
) -> JsResult<JsValue> {
178178
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
179-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
179+
LazyBuiltIn::ensure_init(&builtin);
180180
ordinary_get(obj, key, receiver, context)
181181
}
182182

@@ -188,7 +188,7 @@ pub(crate) fn lazy_set(
188188
context: &mut InternalMethodContext<'_>,
189189
) -> JsResult<bool> {
190190
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
191-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
191+
LazyBuiltIn::ensure_init(&builtin);
192192
ordinary_set(obj, key, value, receiver, context)
193193
}
194194

@@ -198,7 +198,7 @@ pub(crate) fn lazy_delete(
198198
context: &mut InternalMethodContext<'_>,
199199
) -> JsResult<bool> {
200200
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
201-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
201+
LazyBuiltIn::ensure_init(&builtin);
202202
ordinary_delete(obj, key, context)
203203
}
204204

@@ -207,7 +207,7 @@ pub(crate) fn lazy_own_property_keys(
207207
context: &mut Context,
208208
) -> JsResult<Vec<PropertyKey>> {
209209
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
210-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
210+
LazyBuiltIn::ensure_init(&builtin);
211211

212212
ordinary_own_property_keys(obj, context)
213213
}
@@ -218,19 +218,20 @@ pub(crate) fn lazy_construct(
218218
context: &mut Context,
219219
) -> JsResult<CallValue> {
220220
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
221-
let kind = &builtin.borrow().data.kind;
222-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
221+
LazyBuiltIn::ensure_init(&builtin);
222+
let kind = &builtin.borrow().data.kind.clone();
223223

224224
match kind {
225225
BuiltinKind::Ordinary => Err(JsNativeError::typ()
226226
.with_message("not a constructor")
227227
.with_realm(context.realm().clone())
228228
.into()),
229-
BuiltinKind::Function(constructor) => Ok((constructor.internal_methods().__construct__)(
230-
obj,
231-
argument_count,
232-
context,
233-
)?),
229+
BuiltinKind::Function(constructor) => {
230+
let construct = constructor.internal_methods().__construct__;
231+
// builtin needs to be dropped before calling the constructor to avoid a double borrow
232+
drop(builtin);
233+
Ok(construct(obj, argument_count, context)?)
234+
}
234235
}
235236
}
236237

@@ -240,19 +241,18 @@ pub(crate) fn lazy_call(
240241
context: &mut Context,
241242
) -> JsResult<CallValue> {
242243
let builtin: JsObject<LazyBuiltIn> = obj.clone().downcast().expect("obj is not a Builtin");
243-
let kind = &builtin.borrow().data.kind;
244-
245-
LazyBuiltIn::ensure_init(builtin.borrow_mut().data.clone());
246-
244+
LazyBuiltIn::ensure_init(&builtin);
245+
let kind = &builtin.borrow().data.kind.clone();
247246
match kind {
248247
BuiltinKind::Ordinary => Err(JsNativeError::typ()
249248
.with_message("not a constructor")
250249
.with_realm(context.realm().clone())
251250
.into()),
252-
BuiltinKind::Function(function) => Ok((function.internal_methods().__call__)(
253-
obj,
254-
argument_count,
255-
context,
256-
)?),
251+
BuiltinKind::Function(function) => {
252+
let call = function.internal_methods().__call__;
253+
// builtin needs to be dropped before calling the constructor to avoid a double borrow
254+
drop(builtin);
255+
Ok(call(obj, argument_count, context)?)
256+
}
257257
}
258258
}

0 commit comments

Comments
 (0)