mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 12:05:15 +00:00
LibJS: Support instrinsic Object properties with deferred evaluation
For performance, it is desirable to defer evaluation of intrinsics that are stored on the GlobalObject for every created Realm. To support this, Object now maintains a global storage map to store lambdas that will return the associated intrinsic when evaluated. Once accessed, the instrinsic is moved from this global map to normal Object storage. To prevent this flow from becoming observable, when a deferred intrinsic is stored, we still place an empty object in the normal Object storage. This is so we still create the metadata for the object, and in doing so, can preserve insertion order of the Object storage. Otherwise, this will be observable by way of Object.getOwnPropertyDescriptors.
This commit is contained in:
parent
4f08f2f581
commit
12f9f3d9ef
Notes:
sideshowbarker
2024-07-17 04:03:45 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/12f9f3d9ef Pull-request: https://github.com/SerenityOS/serenity/pull/16159 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/awesomekling
2 changed files with 53 additions and 1 deletions
|
@ -24,6 +24,8 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
static HashMap<Object const*, HashMap<FlyString, Object::IntrinsicAccessor>> s_intrinsics;
|
||||
|
||||
// 10.1.12 OrdinaryObjectCreate ( proto [ , additionalInternalSlotsList ] ), https://tc39.es/ecma262/#sec-ordinaryobjectcreate
|
||||
Object* Object::create(Realm& realm, Object* prototype)
|
||||
{
|
||||
|
@ -67,6 +69,11 @@ Object::Object(Shape& shape)
|
|||
m_storage.resize(shape.property_count());
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
s_intrinsics.remove(this);
|
||||
}
|
||||
|
||||
void Object::initialize(Realm&)
|
||||
{
|
||||
}
|
||||
|
@ -970,6 +977,23 @@ ThrowCompletionOr<bool> Object::set_immutable_prototype(Object* prototype)
|
|||
return false;
|
||||
}
|
||||
|
||||
static Optional<Object::IntrinsicAccessor> find_intrinsic_accessor(Object const* object, PropertyKey const& property_key)
|
||||
{
|
||||
if (!property_key.is_string())
|
||||
return {};
|
||||
|
||||
auto intrinsics = s_intrinsics.find(object);
|
||||
if (intrinsics == s_intrinsics.end())
|
||||
return {};
|
||||
|
||||
auto accessor = intrinsics->value.find(property_key.as_string());
|
||||
if (accessor == intrinsics->value.end())
|
||||
return {};
|
||||
|
||||
intrinsics->value.remove(accessor);
|
||||
return move(accessor->value);
|
||||
}
|
||||
|
||||
Optional<ValueAndAttributes> Object::storage_get(PropertyKey const& property_key) const
|
||||
{
|
||||
VERIFY(property_key.is_valid());
|
||||
|
@ -987,9 +1011,14 @@ Optional<ValueAndAttributes> Object::storage_get(PropertyKey const& property_key
|
|||
auto metadata = shape().lookup(property_key.to_string_or_symbol());
|
||||
if (!metadata.has_value())
|
||||
return {};
|
||||
|
||||
if (auto accessor = find_intrinsic_accessor(this, property_key); accessor.has_value())
|
||||
const_cast<Object&>(*this).m_storage[metadata->offset] = (*accessor)(shape().realm());
|
||||
|
||||
value = m_storage[metadata->offset];
|
||||
attributes = metadata->attributes;
|
||||
}
|
||||
|
||||
return ValueAndAttributes { .value = value, .attributes = attributes };
|
||||
}
|
||||
|
||||
|
@ -1013,6 +1042,11 @@ void Object::storage_set(PropertyKey const& property_key, ValueAndAttributes con
|
|||
return;
|
||||
}
|
||||
|
||||
if (property_key.is_string()) {
|
||||
if (auto intrinsics = s_intrinsics.find(this); intrinsics != s_intrinsics.end())
|
||||
intrinsics->value.remove(property_key.as_string());
|
||||
}
|
||||
|
||||
auto property_key_string_or_symbol = property_key.to_string_or_symbol();
|
||||
auto metadata = shape().lookup(property_key_string_or_symbol);
|
||||
|
||||
|
@ -1050,6 +1084,11 @@ void Object::storage_delete(PropertyKey const& property_key)
|
|||
if (property_key.is_number())
|
||||
return m_indexed_properties.remove(property_key.as_number());
|
||||
|
||||
if (property_key.is_string()) {
|
||||
if (auto intrinsics = s_intrinsics.find(this); intrinsics != s_intrinsics.end())
|
||||
intrinsics->value.remove(property_key.as_string());
|
||||
}
|
||||
|
||||
auto metadata = shape().lookup(property_key.to_string_or_symbol());
|
||||
VERIFY(metadata.has_value());
|
||||
|
||||
|
@ -1098,6 +1137,16 @@ void Object::define_direct_accessor(PropertyKey const& property_key, FunctionObj
|
|||
}
|
||||
}
|
||||
|
||||
void Object::define_intrinsic_accessor(PropertyKey const& property_key, PropertyAttributes attributes, IntrinsicAccessor accessor)
|
||||
{
|
||||
VERIFY(property_key.is_string());
|
||||
|
||||
storage_set(property_key, { {}, attributes });
|
||||
|
||||
auto& intrinsics = s_intrinsics.ensure(this);
|
||||
intrinsics.set(property_key.as_string(), move(accessor));
|
||||
}
|
||||
|
||||
void Object::ensure_shape_is_unique()
|
||||
{
|
||||
if (shape().is_unique())
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
static Object* create(Realm&, Object* prototype);
|
||||
|
||||
virtual void initialize(Realm&) override;
|
||||
virtual ~Object() = default;
|
||||
virtual ~Object();
|
||||
|
||||
enum class PropertyKind {
|
||||
Key,
|
||||
|
@ -151,6 +151,9 @@ public:
|
|||
void define_direct_property(PropertyKey const& property_key, Value value, PropertyAttributes attributes) { storage_set(property_key, { value, attributes }); };
|
||||
void define_direct_accessor(PropertyKey const&, FunctionObject* getter, FunctionObject* setter, PropertyAttributes attributes);
|
||||
|
||||
using IntrinsicAccessor = Value (*)(Realm&);
|
||||
virtual void define_intrinsic_accessor(PropertyKey const&, PropertyAttributes attributes, IntrinsicAccessor accessor);
|
||||
|
||||
void define_native_function(Realm&, PropertyKey const&, SafeFunction<ThrowCompletionOr<Value>(VM&)>, i32 length, PropertyAttributes attributes);
|
||||
void define_native_accessor(Realm&, PropertyKey const&, SafeFunction<ThrowCompletionOr<Value>(VM&)> getter, SafeFunction<ThrowCompletionOr<Value>(VM&)> setter, PropertyAttributes attributes);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue