mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 10:17:34 +00:00
LibJS: Add basic monomorphic caching for PutById property access
This patch makes it possible for JS::Object::internal_set() to populate a CacheablePropertyMetadata, and uses this to implement a basic monomorphic cache for the most common form of property write access.
This commit is contained in:
parent
28118623f5
commit
b1b2ca1485
28 changed files with 99 additions and 54 deletions
|
@ -52,7 +52,7 @@ ThrowCompletionOr<Value> ArgumentsObject::internal_get(PropertyKey const& proper
|
|||
}
|
||||
|
||||
// 10.4.4.4 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-arguments-exotic-objects-set-p-v-receiver
|
||||
ThrowCompletionOr<bool> ArgumentsObject::internal_set(PropertyKey const& property_key, Value value, Value receiver)
|
||||
ThrowCompletionOr<bool> ArgumentsObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*)
|
||||
{
|
||||
bool is_mapped = false;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
virtual ThrowCompletionOr<Optional<PropertyDescriptor>> internal_get_own_property(PropertyKey const&) const override;
|
||||
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override;
|
||||
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver) override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
|
||||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
|
||||
|
||||
virtual bool may_interfere_with_indexed_property_access() const final { return true; }
|
||||
|
|
|
@ -1153,6 +1153,8 @@ template void async_function_start(VM&, PromiseCapability const&, NonnullRefPtr<
|
|||
template void async_block_start(VM&, SafeFunction<Completion()> const& async_body, PromiseCapability const&, ExecutionContext&);
|
||||
template void async_function_start(VM&, PromiseCapability const&, SafeFunction<Completion()> const& async_function_body);
|
||||
|
||||
static HashMap<NonnullRefPtr<Statement const>, RefPtr<Bytecode::Executable>> executable_cache;
|
||||
|
||||
// 10.2.1.4 OrdinaryCallEvaluateBody ( F, argumentsList ), https://tc39.es/ecma262/#sec-ordinarycallevaluatebody
|
||||
// 15.8.4 Runtime Semantics: EvaluateAsyncFunctionBody, https://tc39.es/ecma262/#sec-runtime-semantics-evaluatefunctionbody
|
||||
Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
|
||||
|
@ -1166,14 +1168,18 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
|
|||
// This is why FunctionDeclarationInstantiation is invoked in the middle.
|
||||
// The issue is that FunctionDeclarationInstantiation may mark certain functions as hoisted
|
||||
// per Annex B. This affects code generation for FunctionDeclaration nodes.
|
||||
|
||||
if (!m_bytecode_executable) {
|
||||
size_t default_parameter_index = 0;
|
||||
for (auto& parameter : m_formal_parameters) {
|
||||
if (!parameter.default_value)
|
||||
continue;
|
||||
auto executable = TRY(Bytecode::compile(vm, *parameter.default_value, FunctionKind::Normal, DeprecatedString::formatted("default parameter #{} for {}", default_parameter_index, m_name)));
|
||||
m_default_parameter_bytecode_executables.append(move(executable));
|
||||
auto maybe_cached_executable = executable_cache.get(m_ecmascript_code);
|
||||
if (maybe_cached_executable.has_value()) {
|
||||
m_bytecode_executable = maybe_cached_executable.value();
|
||||
} else {
|
||||
size_t default_parameter_index = 0;
|
||||
for (auto& parameter : m_formal_parameters) {
|
||||
if (!parameter.default_value)
|
||||
continue;
|
||||
auto executable = TRY(Bytecode::compile(vm, *parameter.default_value, FunctionKind::Normal, DeprecatedString::formatted("default parameter #{} for {}", default_parameter_index, m_name)));
|
||||
m_default_parameter_bytecode_executables.append(move(executable));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1184,8 +1190,10 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
|
|||
return declaration_result.release_error();
|
||||
}
|
||||
|
||||
if (!m_bytecode_executable)
|
||||
if (!m_bytecode_executable) {
|
||||
m_bytecode_executable = TRY(Bytecode::compile(vm, *m_ecmascript_code, m_kind, m_name));
|
||||
executable_cache.set(m_ecmascript_code, m_bytecode_executable);
|
||||
}
|
||||
|
||||
if (m_kind == FunctionKind::Async) {
|
||||
if (declaration_result.is_throw_completion()) {
|
||||
|
|
|
@ -182,7 +182,7 @@ ThrowCompletionOr<Value> ModuleNamespaceObject::internal_get(PropertyKey const&
|
|||
}
|
||||
|
||||
// 10.4.6.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-set-p-v-receiver
|
||||
ThrowCompletionOr<bool> ModuleNamespaceObject::internal_set(PropertyKey const&, Value, Value)
|
||||
ThrowCompletionOr<bool> ModuleNamespaceObject::internal_set(PropertyKey const&, Value, Value, CacheablePropertyMetadata*)
|
||||
{
|
||||
// 1. Return false.
|
||||
return false;
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override;
|
||||
virtual ThrowCompletionOr<bool> internal_has_property(PropertyKey const&) const override;
|
||||
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver) override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
|
||||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
|
||||
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const override;
|
||||
virtual void initialize(Realm&) override;
|
||||
|
|
|
@ -887,7 +887,7 @@ ThrowCompletionOr<Value> Object::internal_get(PropertyKey const& property_key, V
|
|||
}
|
||||
|
||||
// 10.1.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-set-p-v-receiver
|
||||
ThrowCompletionOr<bool> Object::internal_set(PropertyKey const& property_key, Value value, Value receiver)
|
||||
ThrowCompletionOr<bool> Object::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata* cacheable_metadata)
|
||||
{
|
||||
VERIFY(property_key.is_valid());
|
||||
VERIFY(!value.is_empty());
|
||||
|
@ -897,11 +897,11 @@ ThrowCompletionOr<bool> Object::internal_set(PropertyKey const& property_key, Va
|
|||
auto own_descriptor = TRY(internal_get_own_property(property_key));
|
||||
|
||||
// 3. Return ? OrdinarySetWithOwnDescriptor(O, P, V, Receiver, ownDesc).
|
||||
return ordinary_set_with_own_descriptor(property_key, value, receiver, own_descriptor);
|
||||
return ordinary_set_with_own_descriptor(property_key, value, receiver, own_descriptor, cacheable_metadata);
|
||||
}
|
||||
|
||||
// 10.1.9.2 OrdinarySetWithOwnDescriptor ( O, P, V, Receiver, ownDesc ), https://tc39.es/ecma262/#sec-ordinarysetwithowndescriptor
|
||||
ThrowCompletionOr<bool> Object::ordinary_set_with_own_descriptor(PropertyKey const& property_key, Value value, Value receiver, Optional<PropertyDescriptor> own_descriptor)
|
||||
ThrowCompletionOr<bool> Object::ordinary_set_with_own_descriptor(PropertyKey const& property_key, Value value, Value receiver, Optional<PropertyDescriptor> own_descriptor, CacheablePropertyMetadata* cacheable_metadata)
|
||||
{
|
||||
VERIFY(property_key.is_valid());
|
||||
VERIFY(!value.is_empty());
|
||||
|
@ -957,6 +957,13 @@ ThrowCompletionOr<bool> Object::ordinary_set_with_own_descriptor(PropertyKey con
|
|||
// iii. Let valueDesc be the PropertyDescriptor { [[Value]]: V }.
|
||||
auto value_descriptor = PropertyDescriptor { .value = value };
|
||||
|
||||
if (cacheable_metadata && own_descriptor.has_value() && own_descriptor->property_offset.has_value()) {
|
||||
*cacheable_metadata = CacheablePropertyMetadata {
|
||||
.type = CacheablePropertyMetadata::Type::OwnProperty,
|
||||
.property_offset = own_descriptor->property_offset.value(),
|
||||
};
|
||||
}
|
||||
|
||||
// iv. Return ? Receiver.[[DefineOwnProperty]](P, valueDesc).
|
||||
return TRY(receiver.as_object().internal_define_own_property(property_key, value_descriptor));
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ public:
|
|||
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&);
|
||||
virtual ThrowCompletionOr<bool> internal_has_property(PropertyKey const&) const;
|
||||
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver);
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata* = nullptr);
|
||||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&);
|
||||
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const;
|
||||
|
||||
|
@ -141,7 +141,7 @@ public:
|
|||
// might not hold when property access behaves differently.
|
||||
virtual bool may_interfere_with_indexed_property_access() const { return false; }
|
||||
|
||||
ThrowCompletionOr<bool> ordinary_set_with_own_descriptor(PropertyKey const&, Value, Value, Optional<PropertyDescriptor>);
|
||||
ThrowCompletionOr<bool> ordinary_set_with_own_descriptor(PropertyKey const&, Value, Value, Optional<PropertyDescriptor>, CacheablePropertyMetadata* = nullptr);
|
||||
|
||||
// 10.4.7 Immutable Prototype Exotic Objects, https://tc39.es/ecma262/#sec-immutable-prototype-exotic-objects
|
||||
|
||||
|
@ -193,6 +193,7 @@ public:
|
|||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
Value get_direct(size_t index) const { return m_storage[index]; }
|
||||
void put_direct(size_t index, Value value) { m_storage[index] = value; }
|
||||
|
||||
IndexedProperties const& indexed_properties() const { return m_indexed_properties; }
|
||||
IndexedProperties& indexed_properties() { return m_indexed_properties; }
|
||||
|
|
|
@ -525,7 +525,7 @@ ThrowCompletionOr<Value> ProxyObject::internal_get(PropertyKey const& property_k
|
|||
}
|
||||
|
||||
// 10.5.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver
|
||||
ThrowCompletionOr<bool> ProxyObject::internal_set(PropertyKey const& property_key, Value value, Value receiver)
|
||||
ThrowCompletionOr<bool> ProxyObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override;
|
||||
virtual ThrowCompletionOr<bool> internal_has_property(PropertyKey const&) const override;
|
||||
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver) override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
|
||||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
|
||||
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const override;
|
||||
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
|
||||
|
|
|
@ -314,7 +314,7 @@ public:
|
|||
}
|
||||
|
||||
// 10.4.5.5 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-integer-indexed-exotic-objects-set-p-v-receiver
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const& property_key, Value value, Value receiver) override
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*) override
|
||||
{
|
||||
VERIFY(!value.is_empty());
|
||||
VERIFY(!receiver.is_empty());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue