Skip to content

Commit

Permalink
Cherry-pick 339bfd3. rdar://122509050
Browse files Browse the repository at this point in the history
    [WTF] Add LazyRef & LazyUniqueRef
    https://bugs.webkit.org/show_bug.cgi?id=267830
    rdar://121328458

    Reviewed by Ryosuke Niwa.

    This patch adds LazyRef and LazyUniqueRef. This is similar to LazyProperty in JSC.
    We can set *stateless* lambda in the constructor side of the owner object so that it offers clean interface for lazy initialization,
    which does not mess up the owner object's interface.
    For example,

        LazyUniqueRef<VM, Property> m_property;
        Property& property() { return m_property.get(*this); }

    First parameter is owner, which needs to be passed to `get`. And then, this `get` will automatically initialize if it is not initialized.
    And the initialization code can be freely customized, but you do not need to define it as a VM's member! Instead, you can define it as a lambda inside VM.cpp.

        // This lambda needs to be stateless. So it must not capture anything (otherwise, it hits crash because of RELEASE_ASSERT anyway).
        m_property.initLater(
            [](VM& vm, auto& ref) {
                // You can do whatever. Even you can invoke the other property which can be further lazily initialized (so, it implicitly creates dependency graph of initialization).
                ref.set(Property::create());
                // And further, you can do anything after setting it. So these operations can see Property& via `vm.property()`.
            });

    Or you can set lambda in constructor, so like, VM's constructor list,

        : m_property(
            [](VM& vm, auto& ref) {
                // You can do whatever. Even you can invoke the other property which can be further lazily initialized (so, it implicitly creates dependency graph of initialization).
                ref.set(Property::create());
                // And further, you can do anything after setting it. So these operations can see Property& via `vm.property()`.
            })
        , m_other()
        , ...

    This patch applies this to some of JSC::VM's fields, making definitions much cleaner by moving all messy parts into VM.cpp side and clean up VM.h's interface.

    * Source/JavaScriptCore/runtime/HasOwnPropertyCache.h:
    (JSC::HasOwnPropertyCache::Entry::offsetOfStructureID): Deleted.
    (JSC::HasOwnPropertyCache::Entry::offsetOfImpl): Deleted.
    (JSC::HasOwnPropertyCache::Entry::offsetOfResult): Deleted.
    (JSC::HasOwnPropertyCache::operator delete): Deleted.
    (JSC::HasOwnPropertyCache::create): Deleted.
    (JSC::HasOwnPropertyCache::hash): Deleted.
    (JSC::HasOwnPropertyCache::get): Deleted.
    (JSC::HasOwnPropertyCache::tryAdd): Deleted.
    (JSC::HasOwnPropertyCache::clear): Deleted.
    (JSC::HasOwnPropertyCache::clearBuffer): Deleted.
    (JSC::VM::ensureHasOwnPropertyCache): Deleted.
    * Source/JavaScriptCore/runtime/LazyPropertyInlines.h:
    (JSC::ElementType>::initLater):
    * Source/JavaScriptCore/runtime/VM.cpp:
    (JSC::VM::VM):
    (JSC::VM::~VM):
    (JSC::VM::invalidateStructureChainIntegrity):
    (JSC::VM::ensureWatchdog): Deleted.
    (JSC::VM::ensureHeapProfiler): Deleted.
    (JSC::VM::ensureShadowChicken): Deleted.
    (JSC::VM::ensureMegamorphicCacheSlow): Deleted.
    * Source/JavaScriptCore/runtime/VM.h:
    (JSC::VM::watchdog):
    (JSC::VM::ensureWatchdog):
    (JSC::VM::heapProfiler):
    (JSC::VM::ensureHeapProfiler):
    (JSC::VM::hasOwnPropertyCache):
    (JSC::VM::ensureHasOwnPropertyCache):
    (JSC::VM::megamorphicCache):
    (JSC::VM::ensureMegamorphicCache):
    (JSC::VM::shadowChicken):
    (JSC::VM::ensureShadowChicken):
    (JSC::VM::heapProfiler const): Deleted.
    * Source/WTF/WTF.xcodeproj/project.pbxproj:
    * Source/WTF/wtf/CMakeLists.txt:
    * Source/WTF/wtf/LazyRef.h: Added.
    (WTF::LazyRef::~LazyRef):
    (WTF::LazyRef::isInitialized const):
    (WTF::LazyRef::get const):
    (WTF::LazyRef::get):
    (WTF::LazyRef::getIfExists const):
    (WTF::LazyRef::getIfExists):
    (WTF::LazyRef::initLater):
    (WTF::LazyRef::set):
    (WTF::LazyRef::callFunc):
    * Source/WTF/wtf/LazyUniqueRef.h: Added.
    (WTF::LazyUniqueRef::~LazyUniqueRef):
    (WTF::LazyUniqueRef::isInitialized const):
    (WTF::LazyUniqueRef::get const):
    (WTF::LazyUniqueRef::get):
    (WTF::LazyUniqueRef::getIfExists const):
    (WTF::LazyUniqueRef::getIfExists):
    (WTF::LazyUniqueRef::initLater):
    (WTF::LazyUniqueRef::set):
    (WTF::LazyUniqueRef::callFunc):

    Canonical link: https://commits.webkit.org/273287@main

Identifier: 272448.544@safari-7618-branch
  • Loading branch information
Constellation authored and Dan Robson committed Feb 13, 2024
1 parent 984ca90 commit 483d4b2
Show file tree
Hide file tree
Showing 12 changed files with 473 additions and 66 deletions.
14 changes: 4 additions & 10 deletions Source/JavaScriptCore/runtime/HasOwnPropertyCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@
#include "JSObject.h"
#include "PropertySlot.h"
#include "Structure.h"
#include <wtf/UniqueRef.h>

namespace JSC {

DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(HasOwnPropertyCache);

class HasOwnPropertyCache {
class alignas(8) HasOwnPropertyCache {
static const uint32_t size = 2 * 1024;
static_assert(hasOneBitSet(size), "size should be a power of two.");
public:
Expand All @@ -57,12 +58,12 @@ class HasOwnPropertyCache {
HasOwnPropertyCacheMalloc::free(cache);
}

static HasOwnPropertyCache* create()
static UniqueRef<HasOwnPropertyCache> create()
{
size_t allocationSize = sizeof(Entry) * size;
HasOwnPropertyCache* result = static_cast<HasOwnPropertyCache*>(HasOwnPropertyCacheMalloc::malloc(allocationSize));
result->clearBuffer();
return result;
return UniqueRef { *result };
}

ALWAYS_INLINE static uint32_t hash(StructureID structureID, UniquedStringImpl* impl)
Expand Down Expand Up @@ -129,11 +130,4 @@ class HasOwnPropertyCache {
}
};

ALWAYS_INLINE HasOwnPropertyCache& VM::ensureHasOwnPropertyCache()
{
if (UNLIKELY(!m_hasOwnPropertyCache))
m_hasOwnPropertyCache = std::unique_ptr<HasOwnPropertyCache>(HasOwnPropertyCache::create());
return *m_hasOwnPropertyCache;
}

} // namespace JSC
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/runtime/LazyPropertyInlines.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void LazyProperty<OwnerType, ElementType>::initLater(const Func&)
// may be used for things. We address this problem by indirecting through a global const
// variable. The "theFunc" variable is guaranteed to be native-aligned, i.e. at least a
// multiple of 4.
static const FuncType theFunc = &callFunc<Func>;
static constexpr FuncType theFunc = &callFunc<Func>;
m_pointer = lazyTag | bitwise_cast<uintptr_t>(&theFunc);
}

Expand Down
63 changes: 29 additions & 34 deletions Source/JavaScriptCore/runtime/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,31 @@ VM::VM(VMType vmType, HeapType heapType, WTF::RunLoop* runLoop, bool* success)

VMInspector::instance().add(this);

// Set up lazy initializers.
{
m_hasOwnPropertyCache.initLater([](VM&, auto& ref) {
ref.set(HasOwnPropertyCache::create());
});

m_megamorphicCache.initLater([](VM&, auto& ref) {
ref.set(makeUniqueRef<MegamorphicCache>());
});

m_shadowChicken.initLater([](VM&, auto& ref) {
ref.set(makeUniqueRef<ShadowChicken>());
});

m_heapProfiler.initLater([](VM& vm, auto& ref) {
ref.set(makeUniqueRef<HeapProfiler>(vm));
});

m_watchdog.initLater([](VM& vm, auto& ref) {
ref.set(adoptRef(*new Watchdog(&vm)));
vm.ensureTerminationException();
vm.requestEntryScopeService(EntryScopeService::Watchdog);
});
}

updateSoftReservedZoneSize(Options::softReservedZoneSize());
setLastStackTop(Thread::current());
stringSplitIndice.reserveInitialCapacity(256);
Expand Down Expand Up @@ -432,8 +457,8 @@ VM::~VM()
if (Wasm::Worklist* worklist = Wasm::existingWorklistOrNull())
worklist->stopAllPlansForContext(*this);
#endif
if (UNLIKELY(m_watchdog))
m_watchdog->willDestroyVM(this);
if (auto* watchdog = this->watchdog(); UNLIKELY(watchdog))
watchdog->willDestroyVM(this);
m_traps.willDestroyVM();
m_isInService = false;
WTF::storeStoreFence();
Expand Down Expand Up @@ -565,23 +590,6 @@ VM*& VM::sharedInstanceInternal()
return sharedInstance;
}

Watchdog& VM::ensureWatchdog()
{
if (!m_watchdog) {
m_watchdog = adoptRef(new Watchdog(this));
ensureTerminationException();
requestEntryScopeService(EntryScopeService::Watchdog);
}
return *m_watchdog;
}

HeapProfiler& VM::ensureHeapProfiler()
{
if (!m_heapProfiler)
m_heapProfiler = makeUnique<HeapProfiler>(*this);
return *m_heapProfiler;
}

#if ENABLE(SAMPLING_PROFILER)
SamplingProfiler& VM::ensureSamplingProfiler(Ref<Stopwatch>&& stopwatch)
{
Expand Down Expand Up @@ -1469,13 +1477,6 @@ Ref<Waiter> VM::syncWaiter()
return m_syncWaiter;
}

void VM::ensureShadowChicken()
{
if (m_shadowChicken)
return;
m_shadowChicken = makeUnique<ShadowChicken>();
}

JSCell* VM::sentinelSetBucketSlow()
{
ASSERT(!m_sentinelSetBucket);
Expand Down Expand Up @@ -1759,16 +1760,10 @@ void MicrotaskQueue::visitAggregateImpl(Visitor& visitor)
}
DEFINE_VISIT_AGGREGATE(MicrotaskQueue);

void VM::ensureMegamorphicCacheSlow()
{
ASSERT(!m_megamorphicCache);
m_megamorphicCache = makeUnique<MegamorphicCache>();
}

void VM::invalidateStructureChainIntegrity(StructureChainIntegrityEvent)
{
if (m_megamorphicCache)
m_megamorphicCache->bumpEpoch();
if (auto* megamorphicCache = this->megamorphicCache())
megamorphicCache->bumpEpoch();
}

#if ENABLE(WEBASSEMBLY)
Expand Down
38 changes: 17 additions & 21 deletions Source/JavaScriptCore/runtime/VM.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
#include <wtf/Forward.h>
#include <wtf/Gigacage.h>
#include <wtf/HashMap.h>
#include <wtf/LazyRef.h>
#include <wtf/LazyUniqueRef.h>
#include <wtf/SetForScope.h>
#include <wtf/StackPointer.h>
#include <wtf/Stopwatch.h>
Expand Down Expand Up @@ -322,11 +324,11 @@ class VM : public ThreadSafeRefCounted<VM>, public DoublyLinkedListNode<VM> {
static Ref<VM> createContextGroup(HeapType = HeapType::Small);
JS_EXPORT_PRIVATE ~VM();

Watchdog& ensureWatchdog();
Watchdog* watchdog() { return m_watchdog.get(); }
Watchdog* watchdog() { return m_watchdog.getIfExists(); }
Watchdog& ensureWatchdog() { return m_watchdog.get(*this); }

HeapProfiler* heapProfiler() const { return m_heapProfiler.get(); }
JS_EXPORT_PRIVATE HeapProfiler& ensureHeapProfiler();
HeapProfiler* heapProfiler() { return m_heapProfiler.getIfExists(); }
HeapProfiler& ensureHeapProfiler() { return m_heapProfiler.get(*this); }

bool isAnalyzingHeap() const { return m_activeHeapAnalyzer; }
HeapAnalyzer* activeHeapAnalyzer() const { return m_activeHeapAnalyzer; }
Expand Down Expand Up @@ -842,19 +844,13 @@ class VM : public ThreadSafeRefCounted<VM>, public DoublyLinkedListNode<VM> {

Ref<CompactTDZEnvironmentMap> m_compactVariableMap;

std::unique_ptr<HasOwnPropertyCache> m_hasOwnPropertyCache;
ALWAYS_INLINE HasOwnPropertyCache* hasOwnPropertyCache() { return m_hasOwnPropertyCache.get(); }
HasOwnPropertyCache& ensureHasOwnPropertyCache();
LazyUniqueRef<VM, HasOwnPropertyCache> m_hasOwnPropertyCache;
ALWAYS_INLINE HasOwnPropertyCache* hasOwnPropertyCache() { return m_hasOwnPropertyCache.getIfExists(); }
HasOwnPropertyCache& ensureHasOwnPropertyCache() { return m_hasOwnPropertyCache.get(*this); }

std::unique_ptr<MegamorphicCache> m_megamorphicCache;
ALWAYS_INLINE MegamorphicCache* megamorphicCache() { return m_megamorphicCache.get(); }
JS_EXPORT_PRIVATE void ensureMegamorphicCacheSlow();
MegamorphicCache& ensureMegamorphicCache()
{
if (UNLIKELY(!m_megamorphicCache))
ensureMegamorphicCacheSlow();
return *m_megamorphicCache;
}
LazyUniqueRef<VM, MegamorphicCache> m_megamorphicCache;
ALWAYS_INLINE MegamorphicCache* megamorphicCache() { return m_megamorphicCache.getIfExists(); }
MegamorphicCache& ensureMegamorphicCache() { return m_megamorphicCache.get(*this); }

enum class StructureChainIntegrityEvent : uint8_t {
Add,
Expand Down Expand Up @@ -952,8 +948,8 @@ class VM : public ThreadSafeRefCounted<VM>, public DoublyLinkedListNode<VM> {

BytecodeIntrinsicRegistry& bytecodeIntrinsicRegistry() { return *m_bytecodeIntrinsicRegistry; }

ShadowChicken* shadowChicken() { return m_shadowChicken.get(); }
void ensureShadowChicken();
ShadowChicken* shadowChicken() { return m_shadowChicken.getIfExists(); }
ShadowChicken& ensureShadowChicken() { return m_shadowChicken.get(*this); }

template<typename Func>
void logEvent(CodeBlock*, const char* summary, const Func& func);
Expand Down Expand Up @@ -1122,13 +1118,13 @@ class VM : public ThreadSafeRefCounted<VM>, public DoublyLinkedListNode<VM> {
MicrotaskQueue m_microtaskQueue;
MallocPtr<EncodedJSValue, VMMalloc> m_exceptionFuzzBuffer;
VMTraps m_traps;
RefPtr<Watchdog> m_watchdog;
std::unique_ptr<HeapProfiler> m_heapProfiler;
LazyRef<VM, Watchdog> m_watchdog;
LazyUniqueRef<VM, HeapProfiler> m_heapProfiler;
#if ENABLE(SAMPLING_PROFILER)
RefPtr<SamplingProfiler> m_samplingProfiler;
#endif
std::unique_ptr<FuzzerAgent> m_fuzzerAgent;
std::unique_ptr<ShadowChicken> m_shadowChicken;
LazyUniqueRef<VM, ShadowChicken> m_shadowChicken;
std::unique_ptr<BytecodeIntrinsicRegistry> m_bytecodeIntrinsicRegistry;
uint64_t m_drainMicrotaskDelayScopeCount { 0 };

Expand Down
8 changes: 8 additions & 0 deletions Source/WTF/WTF.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,8 @@
E320BFE52A7CB712003C0B3A /* unumberrangeformatter.h in Headers */ = {isa = PBXBuildFile; fileRef = E320BFE32A7CB712003C0B3A /* unumberrangeformatter.h */; settings = {ATTRIBUTES = (Private, ); }; };
E320BFE62A7CB712003C0B3A /* localematcher.h in Headers */ = {isa = PBXBuildFile; fileRef = E320BFE42A7CB712003C0B3A /* localematcher.h */; settings = {ATTRIBUTES = (Private, ); }; };
E324FAA328C9ADBA007089DF /* StringSearch.h in Headers */ = {isa = PBXBuildFile; fileRef = E324FAA228C9ADBA007089DF /* StringSearch.h */; settings = {ATTRIBUTES = (Private, ); }; };
E32AB5012B5CE35D00B9FAAE /* LazyRef.h in Headers */ = {isa = PBXBuildFile; fileRef = E32AB4FF2B5CE35D00B9FAAE /* LazyRef.h */; settings = {ATTRIBUTES = (Private, ); }; };
E32AB5022B5CE35D00B9FAAE /* LazyUniqueRef.h in Headers */ = {isa = PBXBuildFile; fileRef = E32AB5002B5CE35D00B9FAAE /* LazyUniqueRef.h */; settings = {ATTRIBUTES = (Private, ); }; };
E336674A2722551100259122 /* Int128.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E33667492722550900259122 /* Int128.cpp */; };
E3618AB92AD8C4BA00DA7E43 /* ButterflyArray.h in Headers */ = {isa = PBXBuildFile; fileRef = E3618AB82AD8C4B900DA7E43 /* ButterflyArray.h */; settings = {ATTRIBUTES = (Private, ); }; };
E361DB532891159C00B2A2B8 /* FastFloat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E361DB512891159B00B2A2B8 /* FastFloat.cpp */; };
Expand Down Expand Up @@ -1737,6 +1739,8 @@
E324FAA228C9ADBA007089DF /* StringSearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringSearch.h; sourceTree = "<group>"; };
E32561122611B5B600A72CC5 /* RobinHoodHashSet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RobinHoodHashSet.h; sourceTree = "<group>"; };
E32A207323C5902D0034A092 /* NakedRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NakedRef.h; sourceTree = "<group>"; };
E32AB4FF2B5CE35D00B9FAAE /* LazyRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyRef.h; sourceTree = "<group>"; };
E32AB5002B5CE35D00B9FAAE /* LazyUniqueRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyUniqueRef.h; sourceTree = "<group>"; };
E33667492722550900259122 /* Int128.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Int128.cpp; sourceTree = "<group>"; };
E339C163244B4E8700359DA9 /* DataRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataRef.h; sourceTree = "<group>"; };
E33D5F871FBED66700BF625E /* RecursableLambda.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecursableLambda.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2187,6 +2191,8 @@
7C9692941F66306E00267A9E /* KeyValuePair.h */,
C2BCFC3E1F61D13000C9222C /* Language.cpp */,
C2BCFC3F1F61D13000C9222C /* Language.h */,
E32AB4FF2B5CE35D00B9FAAE /* LazyRef.h */,
E32AB5002B5CE35D00B9FAAE /* LazyUniqueRef.h */,
539EB0621D55284200C82EF7 /* LEBDecoder.h */,
337B2D6826546EAA00DDFD3D /* LikelyDenseUnsignedIntegerSet.cpp */,
337B2D6926546EAA00DDFD3D /* LikelyDenseUnsignedIntegerSet.h */,
Expand Down Expand Up @@ -3208,6 +3214,8 @@
DD3DC86F27A4BF8E007E5B61 /* JSValueMalloc.h in Headers */,
DD3DC99727A4BF8E007E5B61 /* KeyValuePair.h in Headers */,
DD3DC8BF27A4BF8E007E5B61 /* Language.h in Headers */,
E32AB5012B5CE35D00B9FAAE /* LazyRef.h in Headers */,
E32AB5022B5CE35D00B9FAAE /* LazyUniqueRef.h in Headers */,
DDF307D327C086DF006A526F /* LChar.h in Headers */,
DD3DC88927A4BF8E007E5B61 /* LEBDecoder.h in Headers */,
6311592628989A55006A9A12 /* LibraryPathDiagnostics.h in Headers */,
Expand Down
2 changes: 2 additions & 0 deletions Source/WTF/wtf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ set(WTF_PUBLIC_HEADERS
KeyValuePair.h
LEBDecoder.h
Language.h
LazyRef.h
LazyUniqueRef.h
LikelyDenseUnsignedIntegerSet.h
ListDump.h
ListHashSet.h
Expand Down
Loading

0 comments on commit 483d4b2

Please sign in to comment.