diff --git a/core/engine/src/context/intrinsics.rs b/core/engine/src/context/intrinsics.rs index ee809da4f7a..7ee9c09e381 100644 --- a/core/engine/src/context/intrinsics.rs +++ b/core/engine/src/context/intrinsics.rs @@ -5,18 +5,19 @@ use boa_macros::js_str; use crate::{ builtins::{ - iterable::IteratorPrototypes, uri::UriFunctions, Array, Date, IntrinsicObject, Math, - OrdinaryObject, + function::ConstructorKind, iterable::IteratorPrototypes, uri::UriFunctions, Array, Date, + IntrinsicObject, Math, OrdinaryObject, }, js_string, + native_function::NativeFunctionObject, object::{ internal_methods::immutable_prototype::IMMUTABLE_PROTOTYPE_EXOTIC_INTERNAL_METHODS, shape::{shared_shape::template::ObjectTemplate, RootShape}, - JsFunction, JsObject, LazyBuiltIn, Object, CONSTRUCTOR, PROTOTYPE, + BuiltinKind, JsFunction, JsObject, LazyBuiltIn, Object, CONSTRUCTOR, PROTOTYPE, }, property::{Attribute, PropertyKey}, realm::{Realm, RealmInner}, - JsSymbol, + JsSymbol, JsValue, NativeFunction, }; #[cfg(feature = "intl")] @@ -101,11 +102,22 @@ impl StandardConstructor { /// Similar to `with_prototype`, but the prototype is lazily initialized. fn lazy(init: fn(&Realm) -> (), realm_inner: &WeakGc) -> Self { - let constructor = JsFunction::lazy_intrinsic_function(true, init, realm_inner.clone()); + let obj = JsObject::from_proto_and_data( + None, + LazyBuiltIn { + init_and_realm: Some((init, realm_inner.clone())), + kind: BuiltinKind::Function(NativeFunctionObject { + f: NativeFunction::from_fn_ptr(|_, _, _| Ok(JsValue::undefined())), + constructor: Some(ConstructorKind::Base), + realm: None, + }), + }, + ); + let constructor = JsFunction::from_object_unchecked(obj); Self { constructor: constructor.clone(), - prototype: JsObject::lazy_prototype(constructor.clone()), + prototype: JsObject::lazy_prototype(obj.clone()), } } diff --git a/core/engine/src/object/builtins/lazy_prototype.rs b/core/engine/src/object/builtins/lazy_prototype.rs index 470c485cdb1..fcb3a19ab4f 100644 --- a/core/engine/src/object/builtins/lazy_prototype.rs +++ b/core/engine/src/object/builtins/lazy_prototype.rs @@ -21,7 +21,7 @@ use super::{JsFunction, LazyBuiltIn}; #[derive(Clone, Trace, Finalize, Debug)] #[allow(clippy::type_complexity)] pub struct LazyPrototype { - pub(crate) constructor: JsFunction, + pub(crate) constructor: JsObject, } // // SAFETY: Temporary, TODO move back to derived Trace when possible @@ -59,16 +59,11 @@ pub(crate) fn lazy_get_prototype_of( obj: &JsObject, context: &mut Context, ) -> JsResult { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_get_prototype_of(obj, context) } @@ -77,43 +72,28 @@ pub(crate) fn lazy_set_prototype_of( prototype: JsPrototype, context: &mut Context, ) -> JsResult { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_set_prototype_of(obj, prototype, context) } pub(crate) fn lazy_is_extensible(obj: &JsObject, context: &mut Context) -> JsResult { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_is_extensible(obj, context) } pub(crate) fn lazy_prevent_extensions(obj: &JsObject, context: &mut Context) -> JsResult { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_prevent_extensions(obj, context) } @@ -122,16 +102,11 @@ pub(crate) fn lazy_get_own_property( key: &PropertyKey, context: &mut InternalMethodContext<'_>, ) -> JsResult> { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_get_own_property(obj, key, context) } @@ -141,16 +116,11 @@ pub(crate) fn lazy_define_own_property( desc: PropertyDescriptor, context: &mut InternalMethodContext<'_>, ) -> JsResult { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_define_own_property(obj, key, desc, context) } @@ -160,16 +130,11 @@ pub(crate) fn lazy_has_property( key: &PropertyKey, context: &mut InternalMethodContext<'_>, ) -> JsResult { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_has_property(obj, key, context) } @@ -179,16 +144,11 @@ pub(crate) fn lazy_try_get( receiver: JsValue, context: &mut InternalMethodContext<'_>, ) -> JsResult> { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_try_get(obj, key, receiver, context) } @@ -199,16 +159,11 @@ pub(crate) fn lazy_get( receiver: JsValue, context: &mut InternalMethodContext<'_>, ) -> JsResult { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_get(obj, key, receiver, context) } @@ -219,16 +174,11 @@ pub(crate) fn lazy_set( receiver: JsValue, context: &mut InternalMethodContext<'_>, ) -> JsResult { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_set(obj, key, value, receiver, context) } @@ -237,16 +187,11 @@ pub(crate) fn lazy_delete( key: &PropertyKey, context: &mut InternalMethodContext<'_>, ) -> JsResult { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_delete(obj, key, context) } @@ -254,16 +199,11 @@ pub(crate) fn lazy_own_property_keys( obj: &JsObject, context: &mut Context, ) -> JsResult> { - let lazy_prototype: JsObject = - obj.clone().downcast().expect("obj is not a Builtin"); - let lazy_builtin = lazy_prototype - .borrow_mut() - .data - .constructor - .downcast_ref::() - .expect("constructor is not a LazyBuiltIn") - .clone(); - LazyBuiltIn::ensure_init(lazy_builtin); + let lazy_built_in: JsObject = obj + .clone() + .downcast::() + .expect("obj is not a Builtin"); + LazyBuiltIn::ensure_init(lazy_built_in.borrow_mut().data.clone()); ordinary_own_property_keys(obj, context) } diff --git a/core/engine/src/object/jsobject.rs b/core/engine/src/object/jsobject.rs index 30c7cd482a5..82e5ec1385e 100644 --- a/core/engine/src/object/jsobject.rs +++ b/core/engine/src/object/jsobject.rs @@ -24,6 +24,7 @@ use crate::{ }; use boa_gc::{self, Finalize, Gc, GcBox, GcRefCell, Trace, WeakGc}; use boa_macros::js_str; +use once_cell::sync::Lazy; use std::{ cell::RefCell, collections::HashMap, @@ -96,7 +97,7 @@ impl JsObject { } /// Creates a new lazy `JsObject` from its inner object and its vtable. /// This is used for built-in objects that are lazily initialized. - pub(crate) fn lazy_prototype(constructor: JsFunction) -> Self { + pub(crate) fn lazy_prototype(constructor: JsObject) -> Self { Self::from_proto_and_data(None, LazyPrototype { constructor }) }