Changeset 181297 in webkit
- Timestamp:
- Mar 9, 2015 5:09:39 PM (9 years ago)
- Location:
- trunk/Source
- Files:
-
- 1 added
- 17 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/JSWeakObjectMapRefInternal.h
r181214 r181297 42 42 struct OpaqueJSWeakObjectMap : public RefCounted<OpaqueJSWeakObjectMap> { 43 43 public: 44 static PassRefPtr<OpaqueJSWeakObjectMap> create(void* data, JSWeakMapDestroyedCallback callback)44 static Ref<OpaqueJSWeakObjectMap> create(JSC::VM& vm, void* data, JSWeakMapDestroyedCallback callback) 45 45 { 46 return adoptRef( new OpaqueJSWeakObjectMap(data, callback));46 return adoptRef(*new OpaqueJSWeakObjectMap(vm, data, callback)); 47 47 } 48 48 … … 55 55 56 56 private: 57 OpaqueJSWeakObjectMap(void* data, JSWeakMapDestroyedCallback callback) 58 : m_data(data) 57 OpaqueJSWeakObjectMap(JSC::VM& vm, void* data, JSWeakMapDestroyedCallback callback) 58 : m_map(vm) 59 , m_data(data) 59 60 , m_callback(callback) 60 61 { -
trunk/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp
r181214 r181297 33 33 #include "JSCInlines.h" 34 34 #include "Weak.h" 35 #include "WeakGCMapInlines.h" 35 36 #include <wtf/HashMap.h> 36 37 #include <wtf/text/StringHash.h> … … 47 48 ExecState* exec = toJS(context); 48 49 JSLockHolder locker(exec); 49 RefPtr<OpaqueJSWeakObjectMap> map = OpaqueJSWeakObjectMap::create( privateData, callback);50 RefPtr<OpaqueJSWeakObjectMap> map = OpaqueJSWeakObjectMap::create(exec->vm(), privateData, callback); 50 51 exec->lexicalGlobalObject()->registerWeakMap(map.get()); 51 52 return map.get(); -
trunk/Source/JavaScriptCore/API/JSWrapperMap.mm
r181214 r181297 38 38 #import "ObjcRuntimeExtras.h" 39 39 #import "WeakGCMap.h" 40 #import "WeakGCMapInlines.h" 40 41 #import <wtf/HashSet.h> 41 42 #import <wtf/TCSpinLock.h> … … 547 548 JSContext *m_context; 548 549 NSMutableDictionary *m_classMap; 549 JSC::WeakGCMap<id, JSC::JSObject> m_cachedJSWrappers;550 std::unique_ptr<JSC::WeakGCMap<id, JSC::JSObject>> m_cachedJSWrappers; 550 551 NSMapTable *m_cachedObjCWrappers; 551 552 } … … 560 561 NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality; 561 562 m_cachedObjCWrappers = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; 562 563 564 m_cachedJSWrappers = std::make_unique<JSC::WeakGCMap<id, JSC::JSObject>>(toJS([context JSGlobalContextRef])->vm()); 565 563 566 m_context = context; 564 567 m_classMap = [[NSMutableDictionary alloc] init]; … … 591 594 - (JSValue *)jsWrapperForObject:(id)object 592 595 { 593 JSC::JSObject* jsWrapper = m_cachedJSWrappers .get(object);596 JSC::JSObject* jsWrapper = m_cachedJSWrappers->get(object); 594 597 if (jsWrapper) 595 598 return [JSValue valueWithJSValueRef:toRef(jsWrapper) inContext:m_context]; … … 607 610 // (2) A long lived object may rack up many JSValues. When the contexts are released these will unprotect the associated JavaScript objects, 608 611 // but still, would probably nicer if we made it so that only one associated object was required, broadcasting object dealloc. 609 m_cachedJSWrappers .set(object, jsWrapper);612 m_cachedJSWrappers->set(object, jsWrapper); 610 613 return [JSValue valueWithJSValueRef:toRef(jsWrapper) inContext:m_context]; 611 614 } -
trunk/Source/JavaScriptCore/ChangeLog
r181293 r181297 1 2015-03-09 Andreas Kling <akling@apple.com> 2 3 Stale entries in WeakGCMaps are keeping tons of WeakBlocks alive unnecessarily. 4 <https://webkit.org/b/142115> 5 <rdar://problem/19992268> 6 7 Reviewed by Geoffrey Garen. 8 9 Prune stale entries from WeakGCMaps as part of every full garbage collection. 10 This frees up tons of previously-stuck WeakBlocks that were only sitting around 11 with finalized handles waiting to die. 12 13 Note that WeakGCMaps register/unregister themselves with the GC heap in their 14 ctor/dtor, so creating one now requires passing the VM. 15 16 Average time spent in the PruningStaleEntriesFromWeakGCMaps GC phase appears 17 to be between 0.01ms and 0.3ms, though I've seen a few longer ones at ~1.2ms. 18 It seems somewhat excessive to do this on every Eden collection, so it's only 19 doing work in full collections for now. 20 21 Because the GC may now mutate WeakGCMap below object allocation, I've made it 22 so that the classic HashMap::add() optimization can't be used with WeakGCMap. 23 This caused intermittent test failures when originally landed due to having 24 an invalid iterator on the stack after add() inserted a new entry and we 25 proceeded to allocate the new object, triggering GC. 26 27 * API/JSWeakObjectMapRefInternal.h: 28 (OpaqueJSWeakObjectMap::create): 29 (OpaqueJSWeakObjectMap::OpaqueJSWeakObjectMap): 30 * API/JSWeakObjectMapRefPrivate.cpp: 31 * API/JSWrapperMap.mm: 32 (-[JSWrapperMap initWithContext:]): 33 (-[JSWrapperMap jsWrapperForObject:]): Pass VM to WeakGCMap constructor. 34 35 * JavaScriptCore.xcodeproj/project.pbxproj: Add WeakGCMapInlines.h and make 36 it project-private so WebCore clients can access it. 37 38 * heap/Heap.cpp: 39 (JSC::Heap::collect): 40 (JSC::Heap::pruneStaleEntriesFromWeakGCMaps): Added a new GC phase for pruning 41 stale entries from WeakGCMaps. This is only executed during full collections. 42 43 * heap/Heap.h: 44 * heap/HeapInlines.h: 45 (JSC::Heap::registerWeakGCMap): 46 (JSC::Heap::unregisterWeakGCMap): Added a mechanism for WeakGCMaps to register 47 themselves with the Heap and provide a pruning callback. 48 49 * runtime/PrototypeMap.h: 50 (JSC::PrototypeMap::PrototypeMap): 51 * runtime/Structure.cpp: 52 (JSC::StructureTransitionTable::add): Pass VM to WeakGCMap constructor. 53 54 * runtime/JSCInlines.h: Add "WeakGCMapInlines.h" 55 56 * runtime/JSGlobalObject.cpp: Include "WeakGCMapInlines.h" so this builds. 57 58 * runtime/JSString.cpp: 59 (JSC::jsStringWithCacheSlowCase): 60 * runtime/PrototypeMap.cpp: 61 (JSC::PrototypeMap::addPrototype): 62 (JSC::PrototypeMap::emptyObjectStructureForPrototype): Remove HashMap add() 63 optimization since it's not safe in the GC-managed WeakGCMap world. 64 65 * runtime/VM.cpp: 66 (JSC::VM::VM): Pass VM to WeakGCMap constructor. 67 68 * runtime/WeakGCMap.h: 69 (JSC::WeakGCMap::set): 70 (JSC::WeakGCMap::add): 71 (JSC::WeakGCMap::WeakGCMap): Deleted. 72 (JSC::WeakGCMap::gcMap): Deleted. 73 (JSC::WeakGCMap::gcMapIfNeeded): Deleted. 74 * runtime/WeakGCMapInlines.h: Added. 75 (JSC::WeakGCMap::WeakGCMap): 76 (JSC::WeakGCMap::~WeakGCMap): 77 (JSC::WeakGCMap::pruneStaleEntries): Moved ctor, dtor and pruning callback 78 to WeakGCMapInlines.h to fix interdependent header issues. Removed code that 79 prunes WeakGCMap at certain growth milestones and instead rely on the GC 80 callback for housekeeping. 81 1 82 2015-03-09 Ryosuke Niwa <rniwa@webkit.org> 2 83 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r181215 r181297 1434 1434 A7FCC26D17A0B6AA00786D1A /* FTLSwitchCase.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FCC26C17A0B6AA00786D1A /* FTLSwitchCase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1435 1435 A8A4748E151A8306004123FF /* libWTF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A8A4748D151A8306004123FF /* libWTF.a */; }; 1436 AD86A93E1AA4D88D002FE77F /* WeakGCMapInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1436 1437 ADDB1F6318D77DBE009B58A8 /* OpaqueRootSet.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDB1F6218D77DB7009B58A8 /* OpaqueRootSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1437 1438 ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */; }; … … 3154 3155 A8E894330CD0603F00367179 /* JSGlobalObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObject.h; sourceTree = "<group>"; }; 3155 3156 AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyTable.cpp; sourceTree = "<group>"; }; 3157 AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakGCMapInlines.h; sourceTree = "<group>"; }; 3156 3158 ADDB1F6218D77DB7009B58A8 /* OpaqueRootSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpaqueRootSet.h; sourceTree = "<group>"; }; 3157 3159 B59F89371891AD3300D5CCDC /* UnlinkedInstructionStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnlinkedInstructionStream.h; sourceTree = "<group>"; }; … … 4636 4638 FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */, 4637 4639 14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */, 4640 AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */, 4638 4641 A7CA3ADD17DA41AE006538AF /* WeakMapConstructor.cpp */, 4639 4642 A7CA3ADE17DA41AE006538AF /* WeakMapConstructor.h */, … … 5530 5533 0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */, 5531 5534 BC18C3ED0E16F5CD00B34460 /* CallData.h in Headers */, 5535 AD86A93E1AA4D88D002FE77F /* WeakGCMapInlines.h in Headers */, 5532 5536 1429D8DE0ED2205B00B89619 /* CallFrame.h in Headers */, 5533 5537 A7C1EAEF17987AB600299DB2 /* CallFrameInlines.h in Headers */, -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r181215 r181297 1066 1066 1067 1067 reapWeakHandles(); 1068 pruneStaleEntriesFromWeakGCMaps(); 1068 1069 sweepArrayBuffers(); 1069 1070 snapshotMarkedSpace(); … … 1177 1178 GCPHASE(ReapingWeakHandles); 1178 1179 m_objectSpace.reapWeakSets(); 1180 } 1181 1182 void Heap::pruneStaleEntriesFromWeakGCMaps() 1183 { 1184 GCPHASE(PruningStaleEntriesFromWeakGCMaps); 1185 if (m_operationInProgress != FullCollection) 1186 return; 1187 for (auto& pruneCallback : m_weakGCMaps.values()) 1188 pruneCallback(); 1179 1189 } 1180 1190 -
trunk/Source/JavaScriptCore/heap/Heap.h
r181215 r181297 227 227 228 228 static bool isZombified(JSCell* cell) { return *(void**)cell == zombifiedBits; } 229 230 void registerWeakGCMap(void* weakGCMap, std::function<void()> pruningCallback); 231 void unregisterWeakGCMap(void* weakGCMap); 229 232 230 233 private: … … 302 305 303 306 void reapWeakHandles(); 307 void pruneStaleEntriesFromWeakGCMaps(); 304 308 void sweepArrayBuffers(); 305 309 void snapshotMarkedSpace(); … … 394 398 unsigned m_delayedReleaseRecursionCount; 395 399 #endif 400 401 HashMap<void*, std::function<void()>> m_weakGCMaps; 396 402 }; 397 403 -
trunk/Source/JavaScriptCore/heap/HeapInlines.h
r181215 r181297 315 315 return *m_markListSet; 316 316 } 317 318 inline void Heap::registerWeakGCMap(void* weakGCMap, std::function<void()> pruningCallback) 319 { 320 m_weakGCMaps.add(weakGCMap, WTF::move(pruningCallback)); 321 } 322 323 inline void Heap::unregisterWeakGCMap(void* weakGCMap) 324 { 325 m_weakGCMaps.remove(weakGCMap); 326 } 317 327 318 328 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/JSCInlines.h
r181214 r181297 52 52 #include "SlotVisitorInlines.h" 53 53 #include "StructureInlines.h" 54 #include "WeakGCMapInlines.h" 54 55 55 56 #endif // JSCInlines_h -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
r181214 r181297 124 124 #include "SymbolPrototype.h" 125 125 #include "VariableWatchpointSetInlines.h" 126 #include "WeakGCMapInlines.h" 126 127 #include "WeakMapConstructor.h" 127 128 #include "WeakMapPrototype.h" -
trunk/Source/JavaScriptCore/runtime/JSString.cpp
r178928 r181297 438 438 JSString* jsStringWithCacheSlowCase(VM& vm, StringImpl& stringImpl) 439 439 { 440 auto addResult = vm.stringCache.add(&stringImpl, nullptr); 441 if (addResult.isNewEntry) 442 addResult.iterator->value = jsString(&vm, String(stringImpl)); 443 vm.lastCachedString.set(vm, addResult.iterator->value.get()); 444 return addResult.iterator->value.get(); 440 if (JSString* string = vm.stringCache.get(&stringImpl)) 441 return string; 442 443 JSString* string = jsString(&vm, String(stringImpl)); 444 vm.lastCachedString.set(vm, string); 445 return string; 445 446 } 446 447 -
trunk/Source/JavaScriptCore/runtime/PrototypeMap.cpp
r163844 r181297 34 34 void PrototypeMap::addPrototype(JSObject* object) 35 35 { 36 m_prototypes. add(object, object);36 m_prototypes.set(object, object); 37 37 38 38 // Note that this method makes the somewhat odd decision to not check if this … … 55 55 Structure* PrototypeMap::emptyObjectStructureForPrototype(JSObject* prototype, unsigned inlineCapacity) 56 56 { 57 StructureMap::AddResult addResult = m_structures.add(std::make_pair(prototype, inlineCapacity), nullptr);58 if ( !addResult.isNewEntry) {57 auto key = std::make_pair(prototype, inlineCapacity); 58 if (Structure* structure = m_structures.get(key)) { 59 59 ASSERT(isPrototype(prototype)); 60 return addResult.iterator->value.get();60 return structure; 61 61 } 62 62 … … 64 64 Structure* structure = JSFinalObject::createStructure( 65 65 prototype->globalObject()->vm(), prototype->globalObject(), prototype, inlineCapacity); 66 addResult.iterator->value = Weak<Structure>(structure);66 m_structures.set(key, Weak<Structure>(structure)); 67 67 return structure; 68 68 } -
trunk/Source/JavaScriptCore/runtime/PrototypeMap.h
r181214 r181297 34 34 class JSObject; 35 35 class Structure; 36 class VM; 36 37 37 38 // Tracks the canonical structure an object should be allocated with when inheriting from a given prototype. 38 39 class PrototypeMap { 39 40 public: 41 explicit PrototypeMap(VM& vm) 42 : m_prototypes(vm) 43 , m_structures(vm) 44 { 45 } 46 40 47 JS_EXPORT_PRIVATE Structure* emptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity); 41 48 void clearEmptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity); -
trunk/Source/JavaScriptCore/runtime/Structure.cpp
r181214 r181297 37 37 #include "StructureChain.h" 38 38 #include "StructureRareDataInlines.h" 39 #include "WeakGCMapInlines.h" 39 40 #include <wtf/CommaPrinter.h> 40 41 #include <wtf/ProcessID.h> … … 91 92 // This handles the second transition being added 92 93 // (or the first transition being despecified!) 93 setMap(new TransitionMap( ));94 setMap(new TransitionMap(vm)); 94 95 add(vm, existingTransition); 95 96 } -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r181214 r181297 84 84 #include "TypeProfilerLog.h" 85 85 #include "UnlinkedCodeBlock.h" 86 #include "WeakGCMapInlines.h" 86 87 #include "WeakMapData.h" 87 88 #include <wtf/ProcessID.h> … … 154 155 , propertyNames(nullptr) 155 156 , emptyList(new MarkedArgumentBuffer) 157 , stringCache(*this) 158 , prototypeMap(*this) 156 159 , keywords(std::make_unique<Keywords>(*this)) 157 160 , interpreter(0) -
trunk/Source/JavaScriptCore/runtime/WeakGCMap.h
r181214 r181297 1 1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved.2 * Copyright (C) 2009, 2015 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 48 48 typedef typename HashMapType::const_iterator const_iterator; 49 49 50 WeakGCMap() 51 : m_gcThreshold(minGCThreshold) 52 { 53 } 50 explicit WeakGCMap(VM&); 51 ~WeakGCMap(); 54 52 55 53 ValueArg* get(const KeyType& key) const … … 60 58 AddResult set(const KeyType& key, ValueType value) 61 59 { 62 gcMapIfNeeded();63 60 return m_map.set(key, WTF::move(value)); 64 }65 66 ALWAYS_INLINE AddResult add(const KeyType& key, ValueType value)67 {68 gcMapIfNeeded();69 AddResult addResult = m_map.fastAdd(key, nullptr);70 if (!addResult.iterator->value) { // New value or found a zombie value.71 addResult.isNewEntry = true;72 addResult.iterator->value = WTF::move(value);73 }74 return addResult;75 61 } 76 62 … … 104 90 } 105 91 92 void pruneStaleEntries(); 93 106 94 private: 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 131 95 HashMapType m_map; 132 int m_gcThreshold;96 VM& m_vm; 133 97 }; 134 135 template<typename KeyArg, typename RawMappedArg, typename HashArg, typename KeyTraitsArg>136 const int WeakGCMap<KeyArg, RawMappedArg, HashArg, KeyTraitsArg>::minGCThreshold;137 98 138 99 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/WeakGCMapInlines.h
r181293 r181297 1 1 /* 2 * Copyright (C) 201 0Apple Inc. All rights reserved.2 * Copyright (C) 2015 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 24 24 */ 25 25 26 #ifndef JSWeakObjectMapRefInternal_h27 #define JSWeakObjectMapRefInternal_h26 #ifndef WeakGCMapInlines_h 27 #define WeakGCMapInlines_h 28 28 29 #include "HeapInlines.h" 29 30 #include "WeakGCMap.h" 30 #include <wtf/RefCounted.h>31 31 32 32 namespace JSC { 33 33 34 class JSObject; 35 34 template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg> 35 inline WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::WeakGCMap(VM& vm) 36 : m_vm(vm) 37 { 38 vm.heap.registerWeakGCMap(this, [this]() { 39 pruneStaleEntries(); 40 }); 36 41 } 37 42 38 typedef void (*JSWeakMapDestroyedCallback)(struct OpaqueJSWeakObjectMap*, void*); 43 template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg> 44 inline WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::~WeakGCMap() 45 { 46 m_vm.heap.unregisterWeakGCMap(this); 47 } 39 48 40 typedef JSC::WeakGCMap<void*, JSC::JSObject> WeakMapType; 49 template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg> 50 NEVER_INLINE void WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::pruneStaleEntries() 51 { 52 m_map.removeIf([](typename HashMapType::KeyValuePairType& entry) { 53 return !entry.value; 54 }); 55 } 41 56 42 struct OpaqueJSWeakObjectMap : public RefCounted<OpaqueJSWeakObjectMap> { 43 public: 44 static PassRefPtr<OpaqueJSWeakObjectMap> create(void* data, JSWeakMapDestroyedCallback callback) 45 { 46 return adoptRef(new OpaqueJSWeakObjectMap(data, callback)); 47 } 57 } // namespace JSC 48 58 49 WeakMapType& map() { return m_map; } 50 51 ~OpaqueJSWeakObjectMap() 52 { 53 m_callback(this, m_data); 54 } 55 56 private: 57 OpaqueJSWeakObjectMap(void* data, JSWeakMapDestroyedCallback callback) 58 : m_data(data) 59 , m_callback(callback) 60 { 61 } 62 WeakMapType m_map; 63 void* m_data; 64 JSWeakMapDestroyedCallback m_callback; 65 }; 66 67 68 #endif // JSWeakObjectMapInternal_h 59 #endif // WeakGCMapInlines_h -
trunk/Source/WebCore/bindings/js/ScriptCachedFrameData.cpp
r181214 r181297 39 39 #include "PageConsoleClient.h" 40 40 #include "PageGroup.h" 41 #include "ScriptController.h" 41 42 #include <heap/StrongInlines.h> 42 43 #include <profiler/Profile.h> 43 44 #include <runtime/JSLock.h> 44 #include "ScriptController.h"45 #include <runtime/WeakGCMapInlines.h> 45 46 46 47 using namespace JSC;
Note: See TracChangeset
for help on using the changeset viewer.