Changeset 116659 in webkit
- Timestamp:
- May 10, 2012 10:32:39 AM (12 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r116593 r116659 1 2012-05-10 Michael Saboff <msaboff@apple.com> 2 3 Enh: Hash Const JSString in Backing Stores to Save Memory 4 https://bugs.webkit.org/show_bug.cgi?id=86024 5 6 Reviewed by Filip Pizlo. 7 8 During garbage collection, each marking thread keeps a HashMap of 9 strings. While visiting via MarkStack::copyAndAppend(), we check to 10 see if the string we are visiting is already in the HashMap. If not 11 we add it. If so, we change the reference to the current string we're 12 visiting to the prior string. 13 14 To somewhat reduce the performance impact of this change, if a string 15 is unique at the end of a marking it will not be checked during further 16 GC phases. In some cases this won't catch all duplicates, but we are 17 trying to catch the growth of duplicate strings. 18 19 * heap/Heap.cpp: 20 (JSC::Heap::markRoots): 21 * heap/MarkStack.cpp: 22 (JSC::MarkStackThreadSharedData::resetChildren): New method called by the 23 main thread to reset the slave threads. This is primarily done to 24 clear the m_uniqueStrings HashMap. 25 (JSC): 26 (JSC::MarkStackThreadSharedData::markingThreadMain): 27 (JSC::MarkStackThreadSharedData::markingThreadStartFunc): 28 (JSC::MarkStackThreadSharedData::MarkStackThreadSharedData): 29 (JSC::MarkStackThreadSharedData::reset): 30 (JSC::MarkStack::reset): Added call to clear m_uniqueStrings. 31 (JSC::MarkStack::internalAppend): New method that performs the hash consting. 32 (JSC::SlotVisitor::copyAndAppend): Changed to call the new hash consting 33 internalAppend() 34 * heap/MarkStack.h: 35 (MarkStackThreadSharedData): 36 (MarkStack): 37 (JSC::MarkStack::sharedData): 38 * runtime/JSString.h: 39 (JSString): Added m_isHashConstSingleton flag, accessors for the flag and 40 code to initialize the flag. 41 (JSC::JSString::finishCreation): 42 (JSC::JSString::isHashConstSingleton): 43 (JSC::JSString::clearHashConstSingleton): 44 (JSC::JSString::setHashConstSingleton): 45 (JSC::JSRopeString::finishCreation): 46 1 47 2012-05-09 Filip Pizlo <fpizlo@apple.com> 2 48 -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r116044 r116659 657 657 visitor.reset(); 658 658 m_sharedData.reset(); 659 #if ENABLE(PARALLEL_GC) 660 m_sharedData.resetChildren(); 661 #endif 659 662 m_storageSpace.doneCopying(); 660 663 -
trunk/Source/JavaScriptCore/heap/MarkStack.cpp
r113455 r116659 37 37 #include "ScopeChain.h" 38 38 #include "Structure.h" 39 #include "UString.h" 39 40 #include "WriteBarrier.h" 40 41 #include <wtf/MainThread.h> … … 219 220 220 221 #if ENABLE(PARALLEL_GC) 221 void MarkStackThreadSharedData::markingThreadMain() 222 void MarkStackThreadSharedData::resetChildren() 223 { 224 for (unsigned i = 0; i < m_slaveMarkStacks.size(); ++i) 225 m_slaveMarkStacks[i]->reset(); 226 } 227 228 void MarkStackThreadSharedData::markingThreadMain(SlotVisitor* slotVisitor) 222 229 { 223 230 WTF::registerGCThread(); 224 SlotVisitor slotVisitor(*this); 225 ParallelModeEnabler enabler(slotVisitor); 226 slotVisitor.drainFromShared(SlotVisitor::SlaveDrain); 227 } 228 229 void MarkStackThreadSharedData::markingThreadStartFunc(void* shared) 230 { 231 static_cast<MarkStackThreadSharedData*>(shared)->markingThreadMain(); 231 ParallelModeEnabler enabler(*slotVisitor); 232 slotVisitor->drainFromShared(SlotVisitor::SlaveDrain); 233 delete slotVisitor; 234 } 235 236 void MarkStackThreadSharedData::markingThreadStartFunc(void* myVisitor) 237 { 238 SlotVisitor* slotVisitor = static_cast<SlotVisitor*>(myVisitor); 239 slotVisitor->sharedData().markingThreadMain(slotVisitor); 232 240 } 233 241 #endif … … 242 250 #if ENABLE(PARALLEL_GC) 243 251 for (unsigned i = 1; i < Options::numberOfGCMarkers; ++i) { 244 m_markingThreads.append(createThread(markingThreadStartFunc, this, "JavaScriptCore::Marking")); 252 SlotVisitor* slotVisitor = new SlotVisitor(*this); 253 m_slaveMarkStacks.append(slotVisitor); 254 m_markingThreads.append(createThread(markingThreadStartFunc, slotVisitor, "JavaScriptCore::Marking")); 245 255 ASSERT(m_markingThreads.last()); 246 256 } … … 274 284 ASSERT(m_opaqueRoots.isEmpty()); 275 285 #endif 276 277 286 m_weakReferenceHarvesters.removeAll(); 278 287 } … … 287 296 m_opaqueRoots.clear(); 288 297 #endif 298 m_uniqueStrings.clear(); 289 299 } 290 300 … … 487 497 } 488 498 499 inline void MarkStack::internalAppend(JSValue* slot) 500 { 501 ASSERT(slot); 502 JSValue value = *slot; 503 ASSERT(value); 504 if (!value.isCell()) 505 return; 506 507 if (value.isString()) { 508 JSString* string = jsCast<JSString*>(value.asCell()); 509 if (!string->isHashConstSingleton() && string->length() > 1 && !string->isRope()) { 510 UniqueStringMap::AddResult addResult = m_uniqueStrings.add(string->string().impl(), value); 511 if (addResult.isNewEntry) 512 string->setHashConstSingleton(); 513 else { 514 JSValue existingJSValue = addResult.iterator->second; 515 if (value != existingJSValue) 516 jsCast<JSString*>(existingJSValue.asCell())->clearHashConstSingleton(); 517 *slot = existingJSValue; 518 return; 519 } 520 } 521 } 522 523 internalAppend(value.asCell()); 524 } 525 526 489 527 void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsigned length) 490 528 { … … 500 538 if (!value) 501 539 continue; 502 internalAppend( value);540 internalAppend(&newValues[i]); 503 541 } 504 542 -
trunk/Source/JavaScriptCore/heap/MarkStack.h
r108119 r116659 35 35 #include "VTableSpectrum.h" 36 36 #include "WeakReferenceHarvester.h" 37 #include <wtf/Forward.h> 37 38 #include <wtf/HashMap.h> 38 39 #include <wtf/HashSet.h> … … 41 42 #include <wtf/OSAllocator.h> 42 43 #include <wtf/PageBlock.h> 44 #include <wtf/text/StringHash.h> 43 45 44 46 namespace JSC { … … 172 174 173 175 void reset(); 174 176 177 #if ENABLE(PARALLEL_GC) 178 void resetChildren(); 179 #endif 180 175 181 private: 176 182 friend class MarkStack; … … 178 184 179 185 #if ENABLE(PARALLEL_GC) 180 void markingThreadMain( );186 void markingThreadMain(SlotVisitor*); 181 187 static void markingThreadStartFunc(void* heap); 182 188 #endif … … 188 194 189 195 Vector<ThreadIdentifier> m_markingThreads; 196 Vector<MarkStack*> m_slaveMarkStacks; 190 197 191 198 Mutex m_markingLock; … … 222 229 bool containsOpaqueRoot(void*); 223 230 int opaqueRootCount(); 224 231 232 MarkStackThreadSharedData& sharedData() { return m_shared; } 225 233 bool isEmpty() { return m_stack.isEmpty(); } 226 234 … … 228 236 229 237 size_t visitCount() const { return m_visitCount; } 230 238 231 239 #if ENABLE(SIMPLE_HEAP_PROFILING) 232 240 VTableSpectrum m_visitedTypeCounts; … … 252 260 void internalAppend(JSCell*); 253 261 void internalAppend(JSValue); 262 void internalAppend(JSValue*); 254 263 255 264 JS_EXPORT_PRIVATE void mergeOpaqueRoots(); … … 271 280 MarkStackArray m_stack; 272 281 HashSet<void*> m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector. 282 typedef HashMap<StringImpl*, JSValue> UniqueStringMap; 283 UniqueStringMap m_uniqueStrings; 273 284 274 285 #if !ASSERT_DISABLED -
trunk/Source/JavaScriptCore/runtime/JSString.h
r115656 r116659 68 68 friend class SpecializedThunkJIT; 69 69 friend class JSRopeString; 70 friend class MarkStack; 70 71 friend struct ThunkHelpers; 71 72 … … 92 93 m_length = length; 93 94 m_is8Bit = m_value.impl()->is8Bit(); 95 m_isHashConstSingleton = false; 94 96 } 95 97 … … 100 102 m_length = length; 101 103 m_is8Bit = m_value.impl()->is8Bit(); 104 m_isHashConstSingleton = false; 102 105 Heap::heap(this)->reportExtraMemoryCost(cost); 103 106 } … … 109 112 m_length = 0; 110 113 m_is8Bit = true; 114 m_isHashConstSingleton = false; 111 115 } 112 116 … … 162 166 bool isRope() const { return m_value.isNull(); } 163 167 bool is8Bit() const { return m_is8Bit; } 168 bool isHashConstSingleton() const { return m_isHashConstSingleton; } 169 void clearHashConstSingleton() { m_isHashConstSingleton = false; } 170 void setHashConstSingleton() { m_isHashConstSingleton = true; } 164 171 165 172 // A string is represented either by a UString or a rope of fibers. 166 173 bool m_is8Bit : 1; 174 bool m_isHashConstSingleton : 1; 167 175 unsigned m_length; 168 176 mutable UString m_value; … … 234 242 m_length = s1->length() + s2->length(); 235 243 m_is8Bit = (s1->is8Bit() && s2->is8Bit()); 244 m_isHashConstSingleton = false; 236 245 m_fibers[0].set(globalData, this, s1); 237 246 m_fibers[1].set(globalData, this, s2); … … 243 252 m_length = s1->length() + s2->length() + s3->length(); 244 253 m_is8Bit = (s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); 254 m_isHashConstSingleton = false; 245 255 m_fibers[0].set(globalData, this, s1); 246 256 m_fibers[1].set(globalData, this, s2);
Note: See TracChangeset
for help on using the changeset viewer.