Ignore:
Timestamp:
Mar 4, 2015, 12:00:00 PM (10 years ago)
Author:
[email protected]
Message:

Stale entries in WeakGCMaps are keeping tons of WeakBlocks alive unnecessarily.
<https://webkit.org/b/142115>
<rdar://problem/19992268>

Reviewed by Geoffrey Garen.

Prune stale entries from WeakGCMaps as part of every full garbage collection.
This frees up tons of previously-stuck WeakBlocks that were only sitting around
with finalized handles waiting to die.

Note that WeakGCMaps register/unregister themselves with the GC heap in their
ctor/dtor, so creating one now requires passing the VM.

Average time spent in the PruningStaleEntriesFromWeakGCMaps GC phase appears
to be between 0.01ms and 0.3ms, though I've seen a few longer ones at ~1.2ms.
It seems somewhat excessive to do this on every Eden collection, so it's only
doing work in full collections for now.

  • API/JSWeakObjectMapRefInternal.h:

(OpaqueJSWeakObjectMap::create):
(OpaqueJSWeakObjectMap::OpaqueJSWeakObjectMap):

  • API/JSWeakObjectMapRefPrivate.cpp:
  • API/JSWrapperMap.mm:

(-[JSWrapperMap initWithContext:]):
(-[JSWrapperMap jsWrapperForObject:]): Pass VM to WeakGCMap constructor.

  • JavaScriptCore.xcodeproj/project.pbxproj: Add WeakGCMapInlines.h and make

it project-private so WebCore clients can access it.

  • heap/Heap.cpp:

(JSC::Heap::collect):
(JSC::Heap::pruneStaleEntriesFromWeakGCMaps): Added a new GC phase for pruning
stale entries from WeakGCMaps. This is only executed during full collections.

  • heap/Heap.h:
  • heap/HeapInlines.h:

(JSC::Heap::registerWeakGCMap):
(JSC::Heap::unregisterWeakGCMap): Added a mechanism for WeakGCMaps to register
themselves with the Heap and provide a pruning callback.

  • runtime/PrototypeMap.h:

(JSC::PrototypeMap::PrototypeMap):

  • runtime/Structure.cpp:

(JSC::StructureTransitionTable::add): Pass VM to WeakGCMap constructor.

  • runtime/JSCInlines.h: Add "WeakGCMapInlines.h"
  • runtime/JSGlobalObject.cpp: Include "WeakGCMapInlines.h" so this builds.
  • runtime/VM.cpp:

(JSC::VM::VM): Pass VM to WeakGCMap constructor.

  • runtime/WeakGCMap.h:

(JSC::WeakGCMap::set):
(JSC::WeakGCMap::add):
(JSC::WeakGCMap::WeakGCMap): Deleted.
(JSC::WeakGCMap::gcMap): Deleted.
(JSC::WeakGCMap::gcMapIfNeeded): Deleted.

  • runtime/WeakGCMapInlines.h: Added.

(JSC::WeakGCMap::WeakGCMap):
(JSC::WeakGCMap::~WeakGCMap):
(JSC::WeakGCMap::pruneStaleEntries): Moved ctor, dtor and pruning callback
to WeakGCMapInlines.h to fix interdependent header issues. Removed code that
prunes WeakGCMap at certain growth milestones and instead rely on the GC
callback for housekeeping.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/WeakGCMap.h

    r170774 r181010  
    11/*
    2  * Copyright (C) 2009 Apple Inc. All rights reserved.
     2 * Copyright (C) 2009, 2015 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4848    typedef typename HashMapType::const_iterator const_iterator;
    4949
    50     WeakGCMap()
    51         : m_gcThreshold(minGCThreshold)
    52     {
    53     }
     50    explicit WeakGCMap(VM&);
     51    ~WeakGCMap();
    5452
    5553    ValueArg* get(const KeyType& key) const
     
    6058    AddResult set(const KeyType& key, ValueType value)
    6159    {
    62         gcMapIfNeeded();
    6360        return m_map.set(key, WTF::move(value));
    6461    }
     
    6663    ALWAYS_INLINE AddResult add(const KeyType& key, ValueType value)
    6764    {
    68         gcMapIfNeeded();
    6965        AddResult addResult = m_map.fastAdd(key, nullptr);
    7066        if (!addResult.iterator->value) { // New value or found a zombie value.
     
    104100    }
    105101
     102    void pruneStaleEntries();
     103
    106104private:
    107     static const int minGCThreshold = 3;
    108 
    109     NEVER_INLINE void gcMap()
    110     {
    111         Vector<KeyType, 4> zombies;
    112 
    113         for (iterator it = m_map.begin(), end = m_map.end(); it != end; ++it) {
    114             if (!it->value)
    115                 zombies.append(it->key);
    116         }
    117 
    118         for (size_t i = 0; i < zombies.size(); ++i)
    119             m_map.remove(zombies[i]);
    120     }
    121 
    122     void gcMapIfNeeded()
    123     {
    124         if (m_map.size() < m_gcThreshold)
    125             return;
    126 
    127         gcMap();
    128         m_gcThreshold = std::max(minGCThreshold, m_map.size() * 2 - 1);
    129     }
    130 
    131105    HashMapType m_map;
    132     int m_gcThreshold;
     106    VM& m_vm;
    133107};
    134 
    135 template<typename KeyArg, typename RawMappedArg, typename HashArg, typename KeyTraitsArg>
    136 const int WeakGCMap<KeyArg, RawMappedArg, HashArg, KeyTraitsArg>::minGCThreshold;
    137108
    138109} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.