LibJS: Preserve runtime caches across executable swaps
Allow a freshly materialized executable to inherit compatible runtime caches from the executable it replaces. Store template object caches as GC cells so they can be shared safely between executable instances.
This commit is contained in:
parent
76a7091acb
commit
fafba20b1a
3 changed files with 64 additions and 6 deletions
|
|
@ -25,6 +25,7 @@
|
|||
namespace JS::Bytecode {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(Executable);
|
||||
GC_DEFINE_ALLOCATOR(TemplateObjectCache);
|
||||
GC_DEFINE_ALLOCATOR(ObjectPropertyIteratorCacheData);
|
||||
|
||||
InstructionStream::InstructionStream(Vector<u8> bytecode)
|
||||
|
|
@ -179,6 +180,17 @@ size_t PropertyLookupCache::external_memory_size() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
void PropertyLookupCache::copy_from(PropertyLookupCache const& other)
|
||||
{
|
||||
clear();
|
||||
if (auto* data = other.monomorphic_data()) {
|
||||
set_monomorphic_data(new MonomorphicData(*data));
|
||||
return;
|
||||
}
|
||||
if (auto* data = other.polymorphic_data())
|
||||
set_polymorphic_data(new PolymorphicData(*data));
|
||||
}
|
||||
|
||||
void PropertyLookupCache::clear()
|
||||
{
|
||||
if (auto* data = monomorphic_data()) {
|
||||
|
|
@ -252,6 +264,12 @@ size_t ObjectPropertyIteratorCacheData::external_memory_size() const
|
|||
return size;
|
||||
}
|
||||
|
||||
void TemplateObjectCache::visit_edges(Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(cached_template_object);
|
||||
}
|
||||
|
||||
Executable::Executable(
|
||||
InstructionStream bytecode,
|
||||
NonnullOwnPtr<IdentifierTable> identifier_table,
|
||||
|
|
@ -282,7 +300,9 @@ Executable::Executable(
|
|||
property_lookup_caches.resize(number_of_property_lookup_caches);
|
||||
global_variable_caches.resize(number_of_global_variable_caches);
|
||||
environment_coordinate_caches.resize(number_of_environment_coordinate_caches);
|
||||
template_object_caches.resize(number_of_template_object_caches);
|
||||
template_object_caches.ensure_capacity(number_of_template_object_caches);
|
||||
for (size_t i = 0; i < number_of_template_object_caches; ++i)
|
||||
template_object_caches.append(heap().allocate<TemplateObjectCache>());
|
||||
object_shape_caches.resize(number_of_object_shape_caches);
|
||||
object_property_iterator_caches.resize(number_of_object_property_iterator_caches);
|
||||
asm_constants_size = this->constants.size();
|
||||
|
|
@ -541,8 +561,7 @@ void Executable::visit_edges(Visitor& visitor)
|
|||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(constants);
|
||||
for (auto& cache : template_object_caches)
|
||||
visitor.visit(cache.cached_template_object);
|
||||
visitor.visit(template_object_caches);
|
||||
for (auto& cache : object_property_iterator_caches)
|
||||
visitor.visit(cache.data);
|
||||
for (auto& cache : object_property_iterator_caches)
|
||||
|
|
@ -558,6 +577,34 @@ void Executable::visit_edges(Visitor& visitor)
|
|||
property_key_table->visit_edges(visitor);
|
||||
}
|
||||
|
||||
void Executable::copy_runtime_caches_from(Executable const& other)
|
||||
{
|
||||
if (this == &other)
|
||||
return;
|
||||
|
||||
if (property_lookup_caches.size() == other.property_lookup_caches.size()) {
|
||||
for (size_t i = 0; i < property_lookup_caches.size(); ++i)
|
||||
property_lookup_caches[i].copy_from(other.property_lookup_caches[i]);
|
||||
}
|
||||
|
||||
if (global_variable_caches.size() == other.global_variable_caches.size())
|
||||
global_variable_caches = other.global_variable_caches;
|
||||
|
||||
if (environment_coordinate_caches.size() == other.environment_coordinate_caches.size())
|
||||
environment_coordinate_caches = other.environment_coordinate_caches;
|
||||
|
||||
if (template_object_caches.size() == other.template_object_caches.size())
|
||||
template_object_caches = other.template_object_caches;
|
||||
|
||||
if (object_shape_caches.size() == other.object_shape_caches.size())
|
||||
object_shape_caches = other.object_shape_caches;
|
||||
|
||||
if (object_property_iterator_caches.size() == other.object_property_iterator_caches.size()) {
|
||||
for (size_t i = 0; i < object_property_iterator_caches.size(); ++i)
|
||||
object_property_iterator_caches[i].data = other.object_property_iterator_caches[i].data;
|
||||
}
|
||||
}
|
||||
|
||||
size_t Executable::external_memory_size() const
|
||||
{
|
||||
size_t size = bytecode.external_memory_size();
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ struct PropertyLookupCache {
|
|||
[[nodiscard]] Span<Entry> entries();
|
||||
[[nodiscard]] ReadonlySpan<Entry> entries() const;
|
||||
[[nodiscard]] size_t external_memory_size() const;
|
||||
void copy_from(PropertyLookupCache const&);
|
||||
|
||||
void update(Entry::Type type, auto callback)
|
||||
{
|
||||
|
|
@ -194,8 +195,17 @@ struct GlobalVariableCache {
|
|||
|
||||
// https://tc39.es/ecma262/#sec-gettemplateobject
|
||||
// Template objects are cached at the call site.
|
||||
struct TemplateObjectCache {
|
||||
class JS_API TemplateObjectCache final : public Cell {
|
||||
GC_CELL(TemplateObjectCache, Cell);
|
||||
GC_DECLARE_ALLOCATOR(TemplateObjectCache);
|
||||
|
||||
public:
|
||||
virtual ~TemplateObjectCache() override = default;
|
||||
|
||||
GC::Ptr<Array> cached_template_object;
|
||||
|
||||
private:
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
};
|
||||
|
||||
// Cache for object literal shapes.
|
||||
|
|
@ -288,7 +298,7 @@ public:
|
|||
Vector<PropertyLookupCache> property_lookup_caches;
|
||||
Vector<GlobalVariableCache> global_variable_caches;
|
||||
Vector<EnvironmentCoordinate> environment_coordinate_caches;
|
||||
Vector<TemplateObjectCache> template_object_caches;
|
||||
Vector<GC::Ref<TemplateObjectCache>> template_object_caches;
|
||||
Vector<ObjectShapeCache> object_shape_caches;
|
||||
Vector<ObjectPropertyIteratorCache> object_property_iterator_caches;
|
||||
NonnullOwnPtr<StringTable> string_table;
|
||||
|
|
@ -338,6 +348,7 @@ public:
|
|||
}
|
||||
|
||||
[[nodiscard]] COLD Optional<size_t> basic_block_index_for_offset(size_t offset) const;
|
||||
void copy_runtime_caches_from(Executable const&);
|
||||
[[nodiscard]] COLD Optional<ExceptionHandlers const&> exception_handlers_for_offset(size_t offset) const;
|
||||
|
||||
[[nodiscard]] Optional<SourceRange> source_range_at(size_t offset) const;
|
||||
|
|
|
|||
|
|
@ -2143,7 +2143,7 @@ void NewPrimitiveArray::execute_impl(VM& vm) const
|
|||
// 13.2.8.4 GetTemplateObject ( templateLiteral ), https://tc39.es/ecma262/#sec-gettemplateobject
|
||||
void GetTemplateObject::execute_impl(VM& vm) const
|
||||
{
|
||||
auto& cache = vm.current_executable().template_object_caches[m_cache];
|
||||
auto& cache = *vm.current_executable().template_object_caches[m_cache];
|
||||
|
||||
// 1. Let realm be the current Realm Record.
|
||||
auto& realm = *vm.current_realm();
|
||||
|
|
|
|||
Loading…
Reference in a new issue