[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.17-1283-gcf603cf
ggaren at apple.com
ggaren at apple.com
Tue Jan 5 23:48:04 UTC 2010
The following commit has been merged in the webkit-1.1 branch:
commit 696109fe97a753fb4cacc48ba4f7cdca43ab7974
Author: ggaren at apple.com <ggaren at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Sat Dec 12 07:20:27 2009 +0000
Rolled out my last patch because the bots were crashing
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@52047 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/API/JSBase.cpp b/JavaScriptCore/API/JSBase.cpp
index 6c362c4..4a32d35 100644
--- a/JavaScriptCore/API/JSBase.cpp
+++ b/JavaScriptCore/API/JSBase.cpp
@@ -99,7 +99,7 @@ void JSGarbageCollect(JSContextRef ctx)
JSLock lock(globalData.isSharedInstance ? LockForReal : SilenceAssertionsOnly);
if (!globalData.heap.isBusy())
- globalData.heap.collectAllGarbage();
+ globalData.heap.collect();
// FIXME: Perhaps we should trigger a second mark and sweep
// once the garbage collector is done if this is called when
diff --git a/JavaScriptCore/API/JSContextRef.cpp b/JavaScriptCore/API/JSContextRef.cpp
index 92ad396..e6626b7 100644
--- a/JavaScriptCore/API/JSContextRef.cpp
+++ b/JavaScriptCore/API/JSContextRef.cpp
@@ -133,7 +133,7 @@ void JSGlobalContextRelease(JSGlobalContextRef ctx)
ASSERT(!globalData.heap.isBusy());
globalData.heap.destroy();
} else
- globalData.heap.collectAllGarbage();
+ globalData.heap.collect();
globalData.deref();
}
diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 8e5b505..eea5200 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -11,164 +11,6 @@
(WTF::initializeMainThreadPlatform):
(WTF::scheduleDispatchFunctionsOnMainThread):
-2009-12-11 Geoffrey Garen <ggaren at apple.com>
-
- Windows build fix: Export some new symbols.
-
- * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
-
-2009-12-11 Geoffrey Garen <ggaren at apple.com>
-
- Windows build fix: Removed some old exports.
-
- * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
-
-2009-12-11 Geoffrey Garen <ggaren at apple.com>
-
- Windows build fix: Use unsigned instead of uint32_t to avoid dependencies.
-
- * wtf/StdLibExtras.h:
- (WTF::bitCount):
-
-2009-12-11 Geoffrey Garen <ggaren at apple.com>
-
- Reviewed by Sam Weinig.
-
- Changed GC from mark-sweep to mark-allocate.
-
- Added WeakGCMap to keep WebCore blissfully ignorant about objects that
- have become garbage but haven't run their destructors yet.
-
- 1% SunSpider speedup.
- 7.6% v8 speedup (37% splay speedup).
- 17% speedup on bench-alloc-nonretained.js.
- 18% speedup on bench-alloc-retained.js.
-
- * API/JSBase.cpp:
- (JSGarbageCollect):
- * API/JSContextRef.cpp:
- * JavaScriptCore.exp:
- * JavaScriptCore.xcodeproj/project.pbxproj: Updated for renames and new
- files.
-
- * debugger/Debugger.cpp:
- (JSC::Debugger::recompileAllJSFunctions): Updated to use the Collector
- iterator abstraction.
-
- * jsc.cpp:
- (functionGC): Updated for rename.
-
- * runtime/Collector.cpp: Slightly reduced the number of allocations per
- collection, so that small workloads only allocate on collector block,
- rather than two.
-
- (JSC::Heap::Heap): Updated to use the new allocateBlock function.
-
- (JSC::Heap::destroy): Updated to use the new freeBlocks function.
-
- (JSC::Heap::allocateBlock): New function to initialize a block when
- allocating it.
-
- (JSC::Heap::freeBlock): Consolidated the responsibility for running
- destructors into this function.
-
- (JSC::Heap::freeBlocks): Updated to use freeBlock.
-
- (JSC::Heap::recordExtraCost): Sweep the heap in this reporting function,
- so that allocation, which is more common, doesn't have to check extraCost.
-
- (JSC::Heap::heapAllocate): Run destructors right before recycling a
- garbage cell. This has better cache utilization than a separate sweep phase.
-
- (JSC::Heap::resizeBlocks):
- (JSC::Heap::growBlocks):
- (JSC::Heap::shrinkBlocks): New set of functions for managing the size of
- the heap, now that the heap doesn't maintain any information about its
- size.
-
- (JSC::isPointerAligned):
- (JSC::isHalfCellAligned):
- (JSC::isPossibleCell):
- (JSC::isCellAligned):
- (JSC::Heap::markConservatively): Cleaned up this code a bit.
-
- (JSC::Heap::clearMarkBits):
- (JSC::Heap::markedCells): Some helper functions for examining the the mark
- bitmap.
-
- (JSC::Heap::sweep): Simplified this function by using a DeadObjectIterator.
-
- (JSC::Heap::markRoots): Reordered some operations for clarity.
-
- (JSC::Heap::objectCount):
- (JSC::Heap::addToStatistics):
- (JSC::Heap::statistics): Rewrote these functions to calculate an object
- count on demand, since the heap doesn't maintain this information by
- itself.
-
- (JSC::Heap::reset): New function for resetting the heap once we've
- exhausted heap space.
-
- (JSC::Heap::collectAllGarbage): This function matches the old collect()
- behavior, but it's now an uncommon function used only by API.
-
- * runtime/Collector.h:
- (JSC::CollectorBitmap::count):
- (JSC::CollectorBitmap::isEmpty): Added some helper functions for managing
- the collector mark bitmap.
-
- (JSC::Heap::reportExtraMemoryCost): Changed reporting from cell equivalents
- to bytes, so it's easier to understand.
-
- * runtime/CollectorHeapIterator.h:
- (JSC::CollectorHeapIterator::CollectorHeapIterator):
- (JSC::CollectorHeapIterator::operator!=):
- (JSC::CollectorHeapIterator::operator*):
- (JSC::CollectorHeapIterator::advance):
- (JSC::::LiveObjectIterator):
- (JSC::::operator):
- (JSC::::DeadObjectIterator):
- (JSC::::ObjectIterator): New iterators for encapsulating details about
- heap layout, and what's live and dead on the heap.
-
- * runtime/JSArray.cpp:
- (JSC::JSArray::putSlowCase):
- (JSC::JSArray::increaseVectorLength): Delay reporting extra cost until
- we're fully constructed, so the heap mark phase won't visit us in an
- invalid state.
-
- * runtime/JSCell.h:
- (JSC::JSCell::):
- (JSC::JSCell::createDummyStructure):
- (JSC::JSCell::JSCell):
- * runtime/JSGlobalData.cpp:
- (JSC::JSGlobalData::JSGlobalData):
- * runtime/JSGlobalData.h: Added a dummy cell to simplify allocation logic.
-
- * runtime/JSString.h:
- (JSC::jsSubstring): Don't report extra cost for substrings, since they
- share a buffer that's already reported extra cost.
-
- * runtime/Tracing.d:
- * runtime/Tracing.h: Changed these dtrace hooks not to report object
- counts, since they're no longer cheap to compute.
-
- * runtime/UString.h: Updated for renames.
-
- * runtime/WeakGCMap.h: Added.
- (JSC::WeakGCMap::isEmpty):
- (JSC::WeakGCMap::uncheckedGet):
- (JSC::WeakGCMap::uncheckedBegin):
- (JSC::WeakGCMap::uncheckedEnd):
- (JSC::::get):
- (JSC::::take):
- (JSC::::set):
- (JSC::::uncheckedRemove): Mentioned above.
-
- * wtf/StdLibExtras.h:
- (WTF::bitCount): Added a bit population count function, so the heap can
- count live objects to fulfill statistics questions.
-
2009-12-11 Gavin Barraclough <barraclough at apple.com>
Reviewed by Oliver Hunt.
diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp
index 4e3cc75..1c91d36 100644
--- a/JavaScriptCore/JavaScriptCore.exp
+++ b/JavaScriptCore/JavaScriptCore.exp
@@ -180,15 +180,16 @@ __ZN3JSC24createStackOverflowErrorEPNS_9ExecStateE
__ZN3JSC25evaluateInGlobalCallFrameERKNS_7UStringERNS_7JSValueEPNS_14JSGlobalObjectE
__ZN3JSC35createInterruptedExecutionExceptionEPNS_12JSGlobalDataE
__ZN3JSC3NaNE
+__ZN3JSC4Heap11objectCountEv
__ZN3JSC4Heap14primaryHeapEndEv
__ZN3JSC4Heap15recordExtraCostEm
__ZN3JSC4Heap16primaryHeapBeginEv
-__ZN3JSC4Heap17collectAllGarbageEv
__ZN3JSC4Heap17globalObjectCountEv
__ZN3JSC4Heap20protectedObjectCountEv
__ZN3JSC4Heap25protectedObjectTypeCountsEv
__ZN3JSC4Heap26protectedGlobalObjectCountEv
__ZN3JSC4Heap6isBusyEv
+__ZN3JSC4Heap7collectEv
__ZN3JSC4Heap7destroyEv
__ZN3JSC4Heap7protectENS_7JSValueE
__ZN3JSC4Heap8allocateEm
@@ -367,7 +368,6 @@ __ZNK3JSC18PropertyDescriptor6getterEv
__ZNK3JSC18PropertyDescriptor6setterEv
__ZNK3JSC18PropertyDescriptor8writableEv
__ZNK3JSC4Heap10statisticsEv
-__ZNK3JSC4Heap11objectCountEv
__ZNK3JSC6JSCell11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
__ZNK3JSC6JSCell12toThisObjectEPNS_9ExecStateE
__ZNK3JSC6JSCell12toThisStringEPNS_9ExecStateE
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
index a04b3e6..aae8118 100644
--- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
+++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
@@ -62,7 +62,7 @@ EXPORTS
?classInfo at JSCell@JSC@@UBEPBUClassInfo at 2@XZ
?className at JSObject@JSC@@UBE?AVUString at 2@XZ
?collate at Collator@WTF@@QBE?AW4Result at 12@PB_WI0I at Z
- ?collectAllGarbage at Heap@JSC@@QAEXXZ
+ ?collect at Heap@JSC@@QAE_NXZ
?computeHash at Rep@UString at JSC@@SAIPBDH at Z
?computeHash at Rep@UString at JSC@@SAIPB_WH at Z
?configurable at PropertyDescriptor@JSC@@QBE_NXZ
@@ -115,8 +115,8 @@ EXPORTS
?detach at Debugger@JSC@@UAEXPAVJSGlobalObject at 2@@Z
?detachThread at WTF@@YAXI at Z
?didTimeOut at TimeoutChecker@JSC@@QAE_NPAVExecState at 2@@Z
- ?doubleToStringInJavaScriptFormat at WTF@@YAXNQADPAI at Z
?dumpSampleData at JSGlobalData@JSC@@QAEXPAVExecState at 2@@Z
+ ?doubleToStringInJavaScriptFormat at WTF@@YAXNQADPAI at Z
?enumerable at PropertyDescriptor@JSC@@QBE_NXZ
?equal at Identifier@JSC@@SA_NPBURep at UString@2 at PBD@Z
?equal at JSC@@YA_NPBURep at UString@1 at 0@Z
@@ -200,10 +200,12 @@ EXPORTS
?materializePropertyMap at Structure@JSC@@AAEXXZ
?name at InternalFunction@JSC@@QAEABVUString at 2@PAVExecState at 2@@Z
?nonInlineNaN at JSC@@YANXZ
- ?objectCount at Heap@JSC@@QBEIXZ
+ ?objectCount at Heap@JSC@@QAEIXZ
?objectProtoFuncToString at JSC@@YI?AVJSValue at 1@PAVExecState at 1@PAVJSObject at 1@V21 at ABVArgList@1@@Z
?parse at Parser@JSC@@AAEXPAVJSGlobalData at 2@PAHPAVUString at 2@@Z
?parseDateFromNullTerminatedCharacters at WTF@@YANPBD at Z
+ ?primaryHeapBegin at Heap@JSC@@QAE?AV?$CollectorHeapIterator@$0A@@2 at XZ
+ ?primaryHeapEnd at Heap@JSC@@QAE?AV?$CollectorHeapIterator@$0A@@2 at XZ
?profiler at Profiler@JSC@@SAPAV12 at XZ
?protect at Heap@JSC@@QAEXVJSValue at 2@@Z
?protectedGlobalObjectCount at Heap@JSC@@QAEIXZ
diff --git a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 60cd3e4..e766243 100644
--- a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -167,7 +167,6 @@
14BD59C50A3E8F9F00BAF59C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; };
14BD5A300A3E91F600BAF59C /* JSContextRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A290A3E91F600BAF59C /* JSContextRef.cpp */; };
14BD5A320A3E91F600BAF59C /* JSValueRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A2B0A3E91F600BAF59C /* JSValueRef.cpp */; };
- 14BFCE6910CDB1FC00364CCE /* WeakGCMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
14C5242B0F5355E900BA3D04 /* JITStubs.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A6581A0F4E36F4000150FD /* JITStubs.h */; settings = {ATTRIBUTES = (Private, ); }; };
14E9D17B107EC469004DDA21 /* JSGlobalObjectFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */; };
14F3488F0E95EF8A003648BC /* CollectorHeapIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F3488E0E95EF8A003648BC /* CollectorHeapIterator.h */; settings = {ATTRIBUTES = (); }; };
@@ -637,7 +636,6 @@
14BD5A2A0A3E91F600BAF59C /* JSContextRef.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSContextRef.h; sourceTree = "<group>"; };
14BD5A2B0A3E91F600BAF59C /* JSValueRef.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSValueRef.cpp; sourceTree = "<group>"; };
14BD5A2D0A3E91F600BAF59C /* testapi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testapi.c; path = API/tests/testapi.c; sourceTree = "<group>"; };
- 14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakGCMap.h; sourceTree = "<group>"; };
14D792640DAA03FB001A9F05 /* RegisterFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterFile.h; sourceTree = "<group>"; };
14D857740A4696C80032146C /* testapi.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = testapi.js; path = API/tests/testapi.js; sourceTree = "<group>"; };
14DA818E0D99FD2000B0A4FB /* JSActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSActivation.h; sourceTree = "<group>"; };
@@ -1604,7 +1602,6 @@
F692A8850255597D01FF60F7 /* UString.cpp */,
F692A8860255597D01FF60F7 /* UString.h */,
1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */,
- 14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */,
A7C2216810C745E000F97913 /* JSZombie.h */,
A7C2216B10C7469C00F97913 /* JSZombie.cpp */,
);
@@ -2013,7 +2010,6 @@
86CAFEE31035DDE60028A609 /* Executable.h in Headers */,
142D3939103E4560007DCB52 /* NumericStrings.h in Headers */,
A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */,
- 14BFCE6910CDB1FC00364CCE /* WeakGCMap.h in Headers */,
BC87CDB910712AD4000614CF /* JSONObject.lut.h in Headers */,
148CD1D8108CF902008163C6 /* JSContextRefPrivate.h in Headers */,
14A1563210966365006FA260 /* DateInstanceCache.h in Headers */,
diff --git a/JavaScriptCore/debugger/Debugger.cpp b/JavaScriptCore/debugger/Debugger.cpp
index 98d707c..902a802 100644
--- a/JavaScriptCore/debugger/Debugger.cpp
+++ b/JavaScriptCore/debugger/Debugger.cpp
@@ -67,9 +67,8 @@ void Debugger::recompileAllJSFunctions(JSGlobalData* globalData)
FunctionExecutableSet functionExecutables;
SourceProviderMap sourceProviders;
- LiveObjectIterator<PrimaryHeap> it = globalData->heap.primaryHeapBegin();
- LiveObjectIterator<PrimaryHeap> heapEnd = globalData->heap.primaryHeapEnd();
- for ( ; it != heapEnd; ++it) {
+ Heap::iterator heapEnd = globalData->heap.primaryHeapEnd();
+ for (Heap::iterator it = globalData->heap.primaryHeapBegin(); it != heapEnd; ++it) {
if (!(*it)->inherits(&JSFunction::info))
continue;
diff --git a/JavaScriptCore/jsc.cpp b/JavaScriptCore/jsc.cpp
index 6c61889..b6bc0aa 100644
--- a/JavaScriptCore/jsc.cpp
+++ b/JavaScriptCore/jsc.cpp
@@ -194,7 +194,7 @@ JSValue JSC_HOST_CALL functionDebug(ExecState* exec, JSObject*, JSValue, const A
JSValue JSC_HOST_CALL functionGC(ExecState* exec, JSObject*, JSValue, const ArgList&)
{
JSLock lock(SilenceAssertionsOnly);
- exec->heap()->collectAllGarbage();
+ exec->heap()->collect();
return jsUndefined();
}
diff --git a/JavaScriptCore/runtime/Collector.cpp b/JavaScriptCore/runtime/Collector.cpp
index aa32bcf..1630a58 100644
--- a/JavaScriptCore/runtime/Collector.cpp
+++ b/JavaScriptCore/runtime/Collector.cpp
@@ -104,7 +104,7 @@ namespace JSC {
const size_t GROWTH_FACTOR = 2;
const size_t LOW_WATER_FACTOR = 4;
-const size_t ALLOCATIONS_PER_COLLECTION = 3600;
+const size_t ALLOCATIONS_PER_COLLECTION = 4000;
// This value has to be a macro to be used in max() without introducing
// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
#define MIN_ARRAY_SIZE (static_cast<size_t>(14))
@@ -148,7 +148,7 @@ Heap::Heap(JSGlobalData* globalData)
, m_globalData(globalData)
{
ASSERT(globalData);
-
+
#if PLATFORM(SYMBIAN)
// Symbian OpenC supports mmap but currently not the MAP_ANON flag.
// Using fastMalloc() does not properly align blocks on 64k boundaries
@@ -170,12 +170,7 @@ Heap::Heap(JSGlobalData* globalData)
#endif // PLATFORM(SYMBIAN)
memset(&primaryHeap, 0, sizeof(CollectorHeap));
- allocateBlock<PrimaryHeap>();
-
memset(&numberHeap, 0, sizeof(CollectorHeap));
-#if USE(JSVALUE32)
- allocateBlock<NumberHeap>();
-#endif
}
Heap::~Heap()
@@ -198,8 +193,15 @@ void Heap::destroy()
delete m_markListSet;
m_markListSet = 0;
- freeBlocks<PrimaryHeap>();
- freeBlocks<NumberHeap>();
+ sweep<PrimaryHeap>();
+ // No need to sweep number heap, because the JSNumber destructor doesn't do anything.
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(primaryHeap.numLiveObjects == primaryHeap.numZombies);
+#else
+ ASSERT(!primaryHeap.numLiveObjects);
+#endif
+ freeBlocks(&primaryHeap);
+ freeBlocks(&numberHeap);
#if ENABLE(JSC_MULTIPLE_THREADS)
if (m_currentThreadRegistrar) {
@@ -223,6 +225,7 @@ NEVER_INLINE CollectorBlock* Heap::allocateBlock()
{
#if PLATFORM(DARWIN)
vm_address_t address = 0;
+ // FIXME: tag the region as a JavaScriptCore heap when we get a registered VM tag: <rdar://problem/6054788>.
vm_map(current_task(), &address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE | VM_TAG_FOR_COLLECTOR_MEMORY, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
#elif PLATFORM(SYMBIAN)
// Allocate a 64 kb aligned CollectorBlock
@@ -230,6 +233,8 @@ NEVER_INLINE CollectorBlock* Heap::allocateBlock()
if (!mask)
CRASH();
uintptr_t address = reinterpret_cast<uintptr_t>(mask);
+
+ memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
#elif PLATFORM(WINCE)
void* address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#elif PLATFORM(WIN_OS)
@@ -242,6 +247,7 @@ NEVER_INLINE CollectorBlock* Heap::allocateBlock()
#elif HAVE(POSIX_MEMALIGN)
void* address;
posix_memalign(&address, BLOCK_SIZE, BLOCK_SIZE);
+ memset(address, 0, BLOCK_SIZE);
#else
#if ENABLE(JSC_MULTIPLE_THREADS)
@@ -267,22 +273,13 @@ NEVER_INLINE CollectorBlock* Heap::allocateBlock()
munmap(reinterpret_cast<char*>(address + adjust + BLOCK_SIZE), extra - adjust);
address += adjust;
+ memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
#endif
- // Initialize block.
-
CollectorBlock* block = reinterpret_cast<CollectorBlock*>(address);
+ block->freeList = block->cells;
block->heap = this;
block->type = heapType;
- clearMarkBits<heapType>(block);
-
- // heapAllocate assumes that it's safe to call a destructor on any cell in the primary heap.
- if (heapType != NumberHeap) {
- for (size_t i = 0; i < HeapConstants<heapType>::cellsPerBlock; ++i)
- new (block->cells + i) JSCell(JSCell::DummyDestructableCell);
- }
-
- // Add block to blocks vector.
CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
size_t numBlocks = heap.numBlocks;
@@ -304,12 +301,6 @@ NEVER_INLINE void Heap::freeBlock(size_t block)
{
CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
- if (heapType != NumberHeap) {
- ObjectIterator<heapType> it(heap, block);
- ObjectIterator<heapType> end(heap, block + 1);
- for ( ; it != end; ++it)
- (*it)->~JSCell();
- }
freeBlock(heap.blocks[block]);
// swap with the last block so we compact as we go
@@ -343,15 +334,13 @@ NEVER_INLINE void Heap::freeBlock(CollectorBlock* block)
#endif
}
-template <HeapType heapType>
-void Heap::freeBlocks()
+void Heap::freeBlocks(CollectorHeap* heap)
{
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
-
- while (heap.usedBlocks)
- freeBlock<heapType>(0);
- fastFree(heap.blocks);
- memset(&heap, 0, sizeof(CollectorHeap));
+ for (size_t i = 0; i < heap->usedBlocks; ++i)
+ if (heap->blocks[i])
+ freeBlock(heap->blocks[i]);
+ fastFree(heap->blocks);
+ memset(heap, 0, sizeof(CollectorHeap));
}
void Heap::recordExtraCost(size_t cost)
@@ -368,14 +357,6 @@ void Heap::recordExtraCost(size_t cost)
// collecting more frequently as long as it stays alive.
// NOTE: we target the primaryHeap unconditionally as JSNumber doesn't modify cost
- if (primaryHeap.extraCost > maxExtraCost && primaryHeap.extraCost > primaryHeap.usedBlocks * BLOCK_SIZE / 2) {
- // If the last iteration through the heap deallocated blocks, we need
- // to clean up remaining garbage before marking. Otherwise, the conservative
- // marking mechanism might follow a pointer to unmapped memory.
- if (primaryHeap.didShrink)
- sweep<PrimaryHeap>();
- reset();
- }
primaryHeap.extraCost += cost;
}
@@ -383,101 +364,101 @@ template <HeapType heapType> ALWAYS_INLINE void* Heap::heapAllocate(size_t s)
{
typedef typename HeapConstants<heapType>::Block Block;
typedef typename HeapConstants<heapType>::Cell Cell;
-
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+ CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
ASSERT(JSLock::lockCount() > 0);
ASSERT(JSLock::currentThreadIsHoldingLock());
ASSERT_UNUSED(s, s <= HeapConstants<heapType>::cellSize);
ASSERT(heap.operationInProgress == NoOperation);
ASSERT(heapType == PrimaryHeap || heap.extraCost == 0);
+ // FIXME: If another global variable access here doesn't hurt performance
+ // too much, we could CRASH() in NDEBUG builds, which could help ensure we
+ // don't spend any time debugging cases where we allocate inside an object's
+ // deallocation code.
#if COLLECT_ON_EVERY_ALLOCATION
- collectAllGarbage();
- ASSERT(heap.operationInProgress == NoOperation);
+ collect();
#endif
-allocate:
-
- // Fast case: find the next garbage cell and recycle it.
-
- do {
- ASSERT(heap.nextBlock < heap.usedBlocks);
- Block* block = reinterpret_cast<Block*>(heap.blocks[heap.nextBlock]);
- do {
- ASSERT(heap.nextCell < HeapConstants<heapType>::cellsPerBlock);
- if (!block->marked.get(heap.nextCell >> HeapConstants<heapType>::bitmapShift)) { // Always false for the last cell in the block
- Cell* cell = block->cells + heap.nextCell;
- if (heapType != NumberHeap) {
- heap.operationInProgress = Allocation;
- JSCell* imp = reinterpret_cast<JSCell*>(cell);
- imp->~JSCell();
- heap.operationInProgress = NoOperation;
- }
- ++heap.nextCell;
- return cell;
- }
- } while (++heap.nextCell != HeapConstants<heapType>::cellsPerBlock);
- heap.nextCell = 0;
- } while (++heap.nextBlock != heap.usedBlocks);
+ size_t numLiveObjects = heap.numLiveObjects;
+ size_t usedBlocks = heap.usedBlocks;
+ size_t i = heap.firstBlockWithPossibleSpace;
+
+ // if we have a huge amount of extra cost, we'll try to collect even if we still have
+ // free cells left.
+ if (heapType == PrimaryHeap && heap.extraCost > ALLOCATIONS_PER_COLLECTION) {
+ size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
+ size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
+ const size_t newCost = numNewObjects + heap.extraCost;
+ if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect)
+ goto collect;
+ }
- // Slow case: reached the end of the heap. Mark live objects and start over.
+ ASSERT(heap.operationInProgress == NoOperation);
+#ifndef NDEBUG
+ // FIXME: Consider doing this in NDEBUG builds too (see comment above).
+ heap.operationInProgress = Allocation;
+#endif
- reset();
- goto allocate;
-}
+scan:
+ Block* targetBlock;
+ size_t targetBlockUsedCells;
+ if (i != usedBlocks) {
+ targetBlock = reinterpret_cast<Block*>(heap.blocks[i]);
+ targetBlockUsedCells = targetBlock->usedCells;
+ ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock);
+ while (targetBlockUsedCells == HeapConstants<heapType>::cellsPerBlock) {
+ if (++i == usedBlocks)
+ goto collect;
+ targetBlock = reinterpret_cast<Block*>(heap.blocks[i]);
+ targetBlockUsedCells = targetBlock->usedCells;
+ ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock);
+ }
+ heap.firstBlockWithPossibleSpace = i;
+ } else {
-template <HeapType heapType>
-void Heap::resizeBlocks()
-{
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+collect:
+ size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
+ size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
+ const size_t newCost = numNewObjects + heap.extraCost;
- heap.didShrink = false;
+ if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) {
+#ifndef NDEBUG
+ heap.operationInProgress = NoOperation;
+#endif
+ bool foundGarbage = collect();
+ numLiveObjects = heap.numLiveObjects;
+ usedBlocks = heap.usedBlocks;
+ i = heap.firstBlockWithPossibleSpace;
+#ifndef NDEBUG
+ heap.operationInProgress = Allocation;
+#endif
+ if (foundGarbage)
+ goto scan;
+ }
- size_t usedCellCount = markedCells<heapType>();
- size_t minCellCount = usedCellCount + max(ALLOCATIONS_PER_COLLECTION, usedCellCount);
- size_t minBlockCount = (minCellCount + HeapConstants<heapType>::cellsPerBlock - 1) / HeapConstants<heapType>::cellsPerBlock;
+ // didn't find a block, and GC didn't reclaim anything, need to allocate a new block
+ targetBlock = reinterpret_cast<Block*>(allocateBlock<heapType>());
+ heap.firstBlockWithPossibleSpace = heap.usedBlocks - 1;
+ targetBlockUsedCells = 0;
+ }
- size_t maxCellCount = 1.25f * minCellCount;
- size_t maxBlockCount = (maxCellCount + HeapConstants<heapType>::cellsPerBlock - 1) / HeapConstants<heapType>::cellsPerBlock;
+ // find a free spot in the block and detach it from the free list
+ Cell* newCell = targetBlock->freeList;
- if (heap.usedBlocks < minBlockCount)
- growBlocks<heapType>(minBlockCount);
- else if (heap.usedBlocks > maxBlockCount)
- shrinkBlocks<heapType>(maxBlockCount);
-}
+ // "next" field is a cell offset -- 0 means next cell, so a zeroed block is already initialized
+ targetBlock->freeList = (newCell + 1) + newCell->u.freeCell.next;
-template <HeapType heapType>
-void Heap::growBlocks(size_t neededBlocks)
-{
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
- ASSERT(heap.usedBlocks < neededBlocks);
- while (heap.usedBlocks < neededBlocks)
- allocateBlock<heapType>();
-}
+ targetBlock->usedCells = static_cast<uint32_t>(targetBlockUsedCells + 1);
+ heap.numLiveObjects = numLiveObjects + 1;
-template <HeapType heapType>
-void Heap::shrinkBlocks(size_t neededBlocks)
-{
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
- ASSERT(heap.usedBlocks > neededBlocks);
-
- // Clear the always-on last bit, so isEmpty() isn't fooled by it.
- for (size_t i = 0; i < heap.usedBlocks; ++i)
- heap.blocks[i]->marked.clear((HeapConstants<heapType>::cellsPerBlock - 1) >> HeapConstants<heapType>::bitmapShift);
-
- for (size_t i = 0; i != heap.usedBlocks && heap.usedBlocks != neededBlocks; ) {
- if (heap.blocks[i]->marked.isEmpty()) {
- freeBlock<heapType>(i);
- heap.didShrink = true;
- } else
- ++i;
- }
+#ifndef NDEBUG
+ // FIXME: Consider doing this in NDEBUG builds too (see comment above).
+ heap.operationInProgress = NoOperation;
+#endif
- // Reset the always-on last bit.
- for (size_t i = 0; i < heap.usedBlocks; ++i)
- heap.blocks[i]->marked.set((HeapConstants<heapType>::cellsPerBlock - 1) >> HeapConstants<heapType>::bitmapShift);
+ return newCell;
}
void* Heap::allocate(size_t s)
@@ -733,37 +714,10 @@ void Heap::registerThread()
#endif
-inline bool isPointerAligned(void* p)
-{
- return (((intptr_t)(p) & (sizeof(char*) - 1)) == 0);
-}
-
-// Cell size needs to be a power of two for isPossibleCell to be valid.
-COMPILE_ASSERT(sizeof(CollectorCell) % 2 == 0, Collector_cell_size_is_power_of_two);
-
-#if USE(JSVALUE32)
-static bool isHalfCellAligned(void *p)
-{
- return (((intptr_t)(p) & (CELL_MASK >> 1)) == 0);
-}
-
-static inline bool isPossibleCell(void* p)
-{
- return isHalfCellAligned(p) && p;
-}
-
-#else
+#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) & (sizeof(char*) - 1)) == 0)
-static inline bool isCellAligned(void *p)
-{
- return (((intptr_t)(p) & CELL_MASK) == 0);
-}
-
-static inline bool isPossibleCell(void* p)
-{
- return isCellAligned(p) && p;
-}
-#endif
+// cell size needs to be a power of two for this to be valid
+#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0)
void Heap::markConservatively(MarkStack& markStack, void* start, void* end)
{
@@ -774,49 +728,47 @@ void Heap::markConservatively(MarkStack& markStack, void* start, void* end)
}
ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000);
- ASSERT(isPointerAligned(start));
- ASSERT(isPointerAligned(end));
+ ASSERT(IS_POINTER_ALIGNED(start));
+ ASSERT(IS_POINTER_ALIGNED(end));
char** p = static_cast<char**>(start);
char** e = static_cast<char**>(end);
+ size_t usedPrimaryBlocks = primaryHeap.usedBlocks;
+ size_t usedNumberBlocks = numberHeap.usedBlocks;
+ CollectorBlock** primaryBlocks = primaryHeap.blocks;
+ CollectorBlock** numberBlocks = numberHeap.blocks;
+
+ const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
+
while (p != e) {
char* x = *p++;
- if (isPossibleCell(x)) {
+ if (IS_HALF_CELL_ALIGNED(x) && x) {
uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x);
xAsBits &= CELL_ALIGN_MASK;
uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK;
-
- const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
- if (offset > lastCellOffset)
- continue;
-
CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset);
-#if USE(JSVALUE32)
// Mark the the number heap, we can mark these Cells directly to avoid the virtual call cost
- size_t usedNumberBlocks = numberHeap.usedBlocks;
- CollectorBlock** numberBlocks = numberHeap.blocks;
for (size_t block = 0; block < usedNumberBlocks; block++) {
- if (numberBlocks[block] == blockAddr) {
+ if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
Heap::markCell(reinterpret_cast<JSCell*>(xAsBits));
- goto loopEnd;
+ goto endMarkLoop;
}
}
-#endif
+
// Mark the primary heap
- size_t usedPrimaryBlocks = primaryHeap.usedBlocks;
- CollectorBlock** primaryBlocks = primaryHeap.blocks;
for (size_t block = 0; block < usedPrimaryBlocks; block++) {
- if (primaryBlocks[block] != blockAddr)
- continue;
- markStack.append(reinterpret_cast<JSCell*>(xAsBits));
- markStack.drain();
- break;
+ if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
+ if (reinterpret_cast<CollectorCell*>(xAsBits)->u.freeCell.zeroIfFree) {
+ markStack.append(reinterpret_cast<JSCell*>(xAsBits));
+ markStack.drain();
+ }
+ break;
+ }
}
+ endMarkLoop:
+ ;
}
-#if USE(JSVALUE32)
-loopEnd:
-#endif
}
}
@@ -1057,78 +1009,129 @@ void Heap::markProtectedObjects(MarkStack& markStack)
}
}
-template <HeapType heapType>
-void Heap::clearMarkBits()
+template <HeapType heapType> size_t Heap::sweep()
{
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
- for (size_t i = 0; i < heap.usedBlocks; ++i)
- clearMarkBits<heapType>(heap.blocks[i]);
-}
-
-template <HeapType heapType>
-void Heap::clearMarkBits(CollectorBlock* block)
-{
- // heapAllocate assumes that the last cell in every block is marked.
- block->marked.clearAll();
- block->marked.set((HeapConstants<heapType>::cellsPerBlock - 1) >> HeapConstants<heapType>::bitmapShift);
-}
-
-template <HeapType heapType>
-size_t Heap::markedCells(size_t startBlock, size_t startCell) const
-{
- const CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
- ASSERT(startBlock <= heap.usedBlocks);
- ASSERT(startCell < HeapConstants<heapType>::cellsPerBlock);
-
- if (startBlock >= heap.usedBlocks)
- return 0;
-
- size_t result = 0;
- result += heap.blocks[startBlock]->marked.count(startCell);
- for (size_t i = startBlock + 1; i < heap.usedBlocks; ++i)
- result += heap.blocks[i]->marked.count();
-
- return result;
-}
-
-template <HeapType heapType>
-void Heap::sweep()
-{
- ASSERT(heapType != NumberHeap); // The number heap does not contain meaningful destructors.
+ typedef typename HeapConstants<heapType>::Block Block;
+ typedef typename HeapConstants<heapType>::Cell Cell;
+ // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else
CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
-
- ASSERT(heap.operationInProgress == NoOperation);
- if (heap.operationInProgress != NoOperation)
- CRASH();
- heap.operationInProgress = Collection;
+ size_t emptyBlocks = 0;
+ size_t numLiveObjects = heap.numLiveObjects;
+
+ for (size_t block = 0; block < heap.usedBlocks; block++) {
+ Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]);
+
+ size_t usedCells = curBlock->usedCells;
+ Cell* freeList = curBlock->freeList;
+
+ if (usedCells == HeapConstants<heapType>::cellsPerBlock) {
+ // special case with a block where all cells are used -- testing indicates this happens often
+ for (size_t i = 0; i < HeapConstants<heapType>::cellsPerBlock; i++) {
+ if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) {
+ Cell* cell = curBlock->cells + i;
+
+ if (heapType != NumberHeap) {
+ JSCell* imp = reinterpret_cast<JSCell*>(cell);
+ // special case for allocated but uninitialized object
+ // (We don't need this check earlier because nothing prior this point
+ // assumes the object has a valid vptr.)
+ if (cell->u.freeCell.zeroIfFree == 0)
+ continue;
+#if ENABLE(JSC_ZOMBIES)
+ if (!imp->isZombie()) {
+ const ClassInfo* info = imp->classInfo();
+ imp->~JSCell();
+ new (imp) JSZombie(info, JSZombie::leakedZombieStructure());
+ heap.numZombies++;
+ }
+#else
+ imp->~JSCell();
+#endif
+ }
+ --numLiveObjects;
#if !ENABLE(JSC_ZOMBIES)
- Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get();
+ --usedCells;
+
+ // put cell on the free list
+ cell->u.freeCell.zeroIfFree = 0;
+ cell->u.freeCell.next = freeList - (cell + 1);
+ freeList = cell;
#endif
-
- DeadObjectIterator<heapType> it(heap, heap.nextBlock, heap.nextCell);
- DeadObjectIterator<heapType> end(heap, heap.usedBlocks);
- for ( ; it != end; ++it) {
- JSCell* cell = *it;
+ }
+ }
+ } else {
+ size_t minimumCellsToProcess = usedCells;
+ for (size_t i = 0; (i < minimumCellsToProcess) & (i < HeapConstants<heapType>::cellsPerBlock); i++) {
+ Cell* cell = curBlock->cells + i;
+ if (cell->u.freeCell.zeroIfFree == 0) {
+ ++minimumCellsToProcess;
+ } else {
+ if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) {
+ if (heapType != NumberHeap) {
+ JSCell* imp = reinterpret_cast<JSCell*>(cell);
#if ENABLE(JSC_ZOMBIES)
- if (!cell->isZombie()) {
- const ClassInfo* info = cell->classInfo();
- cell->~JSCell();
- new (cell) JSZombie(info, JSZombie::leakedZombieStructure());
- Heap::markCell(cell);
- }
+ if (!imp->isZombie()) {
+ const ClassInfo* info = imp->classInfo();
+ imp->~JSCell();
+ new (imp) JSZombie(info, JSZombie::leakedZombieStructure());
+ heap.numZombies++;
+ }
#else
- cell->~JSCell();
- // Callers of sweep assume it's safe to mark any cell in the heap.
- new (cell) JSCell(dummyMarkableCellStructure);
+ imp->~JSCell();
+#endif
+ }
+#if !ENABLE(JSC_ZOMBIES)
+ --usedCells;
+ --numLiveObjects;
+
+ // put cell on the free list
+ cell->u.freeCell.zeroIfFree = 0;
+ cell->u.freeCell.next = freeList - (cell + 1);
+ freeList = cell;
#endif
+ }
+ }
+ }
+ }
+
+ curBlock->usedCells = static_cast<uint32_t>(usedCells);
+ curBlock->freeList = freeList;
+ curBlock->marked.clearAll();
+
+ if (!usedCells)
+ ++emptyBlocks;
}
+
+ if (heap.numLiveObjects != numLiveObjects)
+ heap.firstBlockWithPossibleSpace = 0;
+
+ heap.numLiveObjects = numLiveObjects;
+ heap.numLiveObjectsAtLastCollect = numLiveObjects;
+ heap.extraCost = 0;
+
+ if (!emptyBlocks)
+ return numLiveObjects;
- heap.operationInProgress = NoOperation;
+ size_t neededCells = 1.25f * (numLiveObjects + max(ALLOCATIONS_PER_COLLECTION, numLiveObjects));
+ size_t neededBlocks = (neededCells + HeapConstants<heapType>::cellsPerBlock - 1) / HeapConstants<heapType>::cellsPerBlock;
+ for (size_t block = 0; block < heap.usedBlocks; block++) {
+ if (heap.usedBlocks <= neededBlocks)
+ break;
+
+ Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]);
+ if (curBlock->usedCells)
+ continue;
+
+ freeBlock<heapType>(block);
+ block--; // Don't move forward a step in this case
+ }
+
+ return numLiveObjects;
}
-void Heap::markRoots()
+bool Heap::collect()
{
#ifndef NDEBUG
if (m_globalData->isSharedInstance) {
@@ -1137,31 +1140,23 @@ void Heap::markRoots()
}
#endif
- ASSERT((primaryHeap.operationInProgress == NoOperation) & (numberHeap.operationInProgress == NoOperation));
- if (!((primaryHeap.operationInProgress == NoOperation) & (numberHeap.operationInProgress == NoOperation)))
+ ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation));
+ if ((primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation))
CRASH();
+ JAVASCRIPTCORE_GC_BEGIN();
primaryHeap.operationInProgress = Collection;
numberHeap.operationInProgress = Collection;
+ // MARK: first mark all referenced objects recursively starting out from the set of root objects
MarkStack& markStack = m_globalData->markStack;
-
- // Reset mark bits.
- clearMarkBits<PrimaryHeap>();
- clearMarkBits<NumberHeap>();
-
- // Mark stack roots.
markStackObjectsConservatively(markStack);
- m_globalData->interpreter->registerFile().markCallFrames(markStack, this);
-
- // Mark explicitly registered roots.
markProtectedObjects(markStack);
-
- // Mark misc. other roots.
if (m_markListSet && m_markListSet->size())
MarkedArgumentBuffer::markLists(markStack, *m_markListSet);
if (m_globalData->exception)
markStack.append(m_globalData->exception);
+ m_globalData->interpreter->registerFile().markCallFrames(markStack, this);
m_globalData->smallStrings.markChildren(markStack);
if (m_globalData->functionCodeBlockBeingReparsed)
m_globalData->functionCodeBlockBeingReparsed->markAggregate(markStack);
@@ -1170,41 +1165,41 @@ void Heap::markRoots()
markStack.drain();
markStack.compact();
+ JAVASCRIPTCORE_GC_MARKED();
+
+ size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
+ size_t numLiveObjects = sweep<PrimaryHeap>();
+ numLiveObjects += sweep<NumberHeap>();
primaryHeap.operationInProgress = NoOperation;
numberHeap.operationInProgress = NoOperation;
-}
+ JAVASCRIPTCORE_GC_END(originalLiveObjects, numLiveObjects);
-size_t Heap::objectCount() const
-{
- return objectCount<PrimaryHeap>() + objectCount<NumberHeap>();
+ return numLiveObjects < originalLiveObjects;
}
-template <HeapType heapType>
-size_t Heap::objectCount() const
+size_t Heap::objectCount()
{
- const CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
-
- return heap.nextBlock * HeapConstants<heapType>::cellsPerBlock // allocated full blocks
- + heap.nextCell // allocated cells in current block
- + markedCells<heapType>(heap.nextBlock, heap.nextCell) // marked cells in remainder of heap
- - heap.usedBlocks; // 1 cell per block is a dummy sentinel
+ return primaryHeap.numLiveObjects + numberHeap.numLiveObjects - m_globalData->smallStrings.count();
}
template <HeapType heapType>
-void Heap::addToStatistics(Heap::Statistics& statistics) const
+static void addToStatistics(Heap::Statistics& statistics, const CollectorHeap& heap)
{
- const CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
-
- statistics.size += heap.usedBlocks * BLOCK_SIZE;
- statistics.free += heap.usedBlocks * BLOCK_SIZE - (objectCount<heapType>() * HeapConstants<heapType>::cellSize);
+ typedef HeapConstants<heapType> HC;
+ for (size_t i = 0; i < heap.usedBlocks; ++i) {
+ if (heap.blocks[i]) {
+ statistics.size += BLOCK_SIZE;
+ statistics.free += (HC::cellsPerBlock - heap.blocks[i]->usedCells) * HC::cellSize;
+ }
+ }
}
Heap::Statistics Heap::statistics() const
{
Statistics statistics = { 0, 0 };
- addToStatistics<PrimaryHeap>(statistics);
- addToStatistics<NumberHeap>(statistics);
+ JSC::addToStatistics<PrimaryHeap>(statistics, primaryHeap);
+ JSC::addToStatistics<NumberHeap>(statistics, numberHeap);
return statistics;
}
@@ -1276,68 +1271,14 @@ bool Heap::isBusy()
return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation);
}
-void Heap::reset()
-{
- JAVASCRIPTCORE_GC_BEGIN();
-
- markRoots();
-
- JAVASCRIPTCORE_GC_MARKED();
-
- primaryHeap.nextCell = 0;
- primaryHeap.nextBlock = 0;
- primaryHeap.extraCost = 0;
-#if ENABLE(JSC_ZOMBIES)
- sweep<PrimaryHeap>();
-#endif
- resizeBlocks<PrimaryHeap>();
-
-#if USE(JSVALUE32)
- numberHeap.nextCell = 0;
- numberHeap.nextBlock = 0;
- resizeBlocks<NumberHeap>();
-#endif
-
- JAVASCRIPTCORE_GC_END();
-}
-
-void Heap::collectAllGarbage()
-{
- JAVASCRIPTCORE_GC_BEGIN();
-
- // If the last iteration through the heap deallocated blocks, we need
- // to clean up remaining garbage before marking. Otherwise, the conservative
- // marking mechanism might follow a pointer to unmapped memory.
- if (primaryHeap.didShrink)
- sweep<PrimaryHeap>();
-
- markRoots();
-
- JAVASCRIPTCORE_GC_MARKED();
-
- primaryHeap.nextCell = 0;
- primaryHeap.nextBlock = 0;
- primaryHeap.extraCost = 0;
- sweep<PrimaryHeap>();
- resizeBlocks<PrimaryHeap>();
-
-#if USE(JSVALUE32)
- numberHeap.nextCell = 0;
- numberHeap.nextBlock = 0;
- resizeBlocks<NumberHeap>();
-#endif
-
- JAVASCRIPTCORE_GC_END();
-}
-
-LiveObjectIterator<PrimaryHeap> Heap::primaryHeapBegin()
+Heap::iterator Heap::primaryHeapBegin()
{
- return LiveObjectIterator<PrimaryHeap>(primaryHeap, 0);
+ return iterator(primaryHeap.blocks, primaryHeap.blocks + primaryHeap.usedBlocks);
}
-LiveObjectIterator<PrimaryHeap> Heap::primaryHeapEnd()
+Heap::iterator Heap::primaryHeapEnd()
{
- return LiveObjectIterator<PrimaryHeap>(primaryHeap, primaryHeap.usedBlocks);
+ return iterator(primaryHeap.blocks + primaryHeap.usedBlocks, primaryHeap.blocks + primaryHeap.usedBlocks);
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/Collector.h b/JavaScriptCore/runtime/Collector.h
index c86ca83..9128701 100644
--- a/JavaScriptCore/runtime/Collector.h
+++ b/JavaScriptCore/runtime/Collector.h
@@ -28,9 +28,9 @@
#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
#include <wtf/OwnPtr.h>
-#include <wtf/StdLibExtras.h>
#include <wtf/Threading.h>
+// This is supremely lame that we require pthreads to build on windows.
#if ENABLE(JSC_MULTIPLE_THREADS)
#include <pthread.h>
#endif
@@ -49,19 +49,20 @@ namespace JSC {
enum OperationInProgress { NoOperation, Allocation, Collection };
enum HeapType { PrimaryHeap, NumberHeap };
- template <HeapType> class LiveObjectIterator;
+ template <HeapType> class CollectorHeapIterator;
struct CollectorHeap {
- size_t nextBlock;
- size_t nextCell;
-
CollectorBlock** blocks;
size_t numBlocks;
size_t usedBlocks;
+ size_t firstBlockWithPossibleSpace;
+ size_t numLiveObjects;
+ size_t numLiveObjectsAtLastCollect;
size_t extraCost;
-
- bool didShrink;
+#if ENABLE(JSC_ZOMBIES)
+ size_t numZombies;
+#endif
OperationInProgress operationInProgress;
};
@@ -69,21 +70,21 @@ namespace JSC {
class Heap : public Noncopyable {
public:
class Thread;
+ typedef CollectorHeapIterator<PrimaryHeap> iterator;
void destroy();
void* allocateNumber(size_t);
void* allocate(size_t);
+ bool collect();
bool isBusy(); // true if an allocation or collection is in progress
- void collectAllGarbage();
- static const size_t minExtraCost = 256;
- static const size_t maxExtraCost = 1024 * 1024;
+ static const size_t minExtraCostSize = 256;
void reportExtraMemoryCost(size_t cost);
- size_t objectCount() const;
+ size_t objectCount();
struct Statistics {
size_t size;
size_t free;
@@ -113,14 +114,13 @@ namespace JSC {
JSGlobalData* globalData() const { return m_globalData; }
static bool isNumber(JSCell*);
- LiveObjectIterator<PrimaryHeap> primaryHeapBegin();
- LiveObjectIterator<PrimaryHeap> primaryHeapEnd();
+ // Iterators for the object heap.
+ iterator primaryHeapBegin();
+ iterator primaryHeapEnd();
private:
template <HeapType heapType> void* heapAllocate(size_t);
- void reset();
- void collectRemainingGarbage();
- template <HeapType heapType> void sweep();
+ template <HeapType heapType> size_t sweep();
static CollectorBlock* cellBlock(const JSCell*);
static size_t cellOffset(const JSCell*);
@@ -131,20 +131,9 @@ namespace JSC {
template <HeapType heapType> NEVER_INLINE CollectorBlock* allocateBlock();
template <HeapType heapType> NEVER_INLINE void freeBlock(size_t);
NEVER_INLINE void freeBlock(CollectorBlock*);
- template <HeapType heapType> void freeBlocks();
- template <HeapType heapType> void resizeBlocks();
- template <HeapType heapType> void growBlocks(size_t neededBlocks);
- template <HeapType heapType> void shrinkBlocks(size_t neededBlocks);
- template <HeapType heapType> void clearMarkBits();
- template <HeapType heapType> void clearMarkBits(CollectorBlock*);
- template <HeapType heapType> size_t markedCells(size_t startBlock = 0, size_t startCell = 0) const;
+ void freeBlocks(CollectorHeap*);
void recordExtraCost(size_t);
-
- template <HeapType heapType> void addToStatistics(Statistics&) const;
- template <HeapType heapType> size_t objectCount() const;
-
- void markRoots();
void markProtectedObjects(MarkStack&);
void markCurrentThreadConservatively(MarkStack&);
void markCurrentThreadConservativelyInternal(MarkStack&);
@@ -200,49 +189,44 @@ namespace JSC {
const size_t SMALL_CELL_SIZE = CELL_SIZE / 2;
const size_t CELL_MASK = CELL_SIZE - 1;
const size_t CELL_ALIGN_MASK = ~CELL_MASK;
- const size_t CELLS_PER_BLOCK = (BLOCK_SIZE - sizeof(Heap*) - sizeof(HeapType)) * 8 * CELL_SIZE / (8 * CELL_SIZE + 1) / CELL_SIZE; // one bitmap byte can represent 8 cells.
-
+ const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2);
const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK;
const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8;
const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t);
-
+
struct CollectorBitmap {
uint32_t bits[BITMAP_WORDS];
bool get(size_t n) const { return !!(bits[n >> 5] & (1 << (n & 0x1F))); }
void set(size_t n) { bits[n >> 5] |= (1 << (n & 0x1F)); }
void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); }
void clearAll() { memset(bits, 0, sizeof(bits)); }
- size_t count(size_t startCell = 0)
- {
- size_t result = 0;
- for ( ; (startCell & 0x1F) != 0; ++startCell) {
- if (get(startCell))
- ++result;
- }
- for (size_t i = startCell >> 5; i < BITMAP_WORDS; ++i)
- result += WTF::bitCount(bits[i]);
- return result;
- }
- size_t isEmpty() // Much more efficient than testing count() == 0.
- {
- for (size_t i = 0; i < BITMAP_WORDS; ++i)
- if (bits[i] != 0)
- return false;
- return true;
- }
};
struct CollectorCell {
- double memory[CELL_ARRAY_LENGTH];
+ union {
+ double memory[CELL_ARRAY_LENGTH];
+ struct {
+ void* zeroIfFree;
+ ptrdiff_t next;
+ } freeCell;
+ } u;
};
struct SmallCollectorCell {
- double memory[CELL_ARRAY_LENGTH / 2];
+ union {
+ double memory[CELL_ARRAY_LENGTH / 2];
+ struct {
+ void* zeroIfFree;
+ ptrdiff_t next;
+ } freeCell;
+ } u;
};
class CollectorBlock {
public:
CollectorCell cells[CELLS_PER_BLOCK];
+ uint32_t usedCells;
+ CollectorCell* freeList;
CollectorBitmap marked;
Heap* heap;
HeapType type;
@@ -251,6 +235,8 @@ namespace JSC {
class SmallCellCollectorBlock {
public:
SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK];
+ uint32_t usedCells;
+ SmallCollectorCell* freeList;
CollectorBitmap marked;
Heap* heap;
HeapType type;
@@ -301,8 +287,8 @@ namespace JSC {
inline void Heap::reportExtraMemoryCost(size_t cost)
{
- if (cost > minExtraCost)
- recordExtraCost(cost);
+ if (cost > minExtraCostSize)
+ recordExtraCost(cost / (CELL_SIZE * 2));
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/CollectorHeapIterator.h b/JavaScriptCore/runtime/CollectorHeapIterator.h
index cdd6702..e38a852 100644
--- a/JavaScriptCore/runtime/CollectorHeapIterator.h
+++ b/JavaScriptCore/runtime/CollectorHeapIterator.h
@@ -31,117 +31,58 @@
namespace JSC {
- class CollectorHeapIterator {
+ template <HeapType heapType> class CollectorHeapIterator {
public:
- bool operator!=(const CollectorHeapIterator& other);
+ CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock);
+
+ bool operator!=(const CollectorHeapIterator<heapType>& other) { return m_block != other.m_block || m_cell != other.m_cell; }
+ CollectorHeapIterator<heapType>& operator++();
JSCell* operator*() const;
- protected:
- CollectorHeapIterator(CollectorHeap&, size_t startBlock, size_t startCell);
- void advance(size_t cellsPerBlock);
-
- CollectorHeap& m_heap;
- size_t m_block;
- size_t m_cell;
- };
-
- template <HeapType heapType>
- class LiveObjectIterator : public CollectorHeapIterator {
- public:
- LiveObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0);
- LiveObjectIterator<heapType>& operator++();
- };
-
- template <HeapType heapType>
- class DeadObjectIterator : public CollectorHeapIterator {
- public:
- DeadObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0);
- DeadObjectIterator<heapType>& operator++();
- };
-
- template <HeapType heapType>
- class ObjectIterator : public CollectorHeapIterator {
- public:
- ObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0);
- ObjectIterator<heapType>& operator++();
+ private:
+ typedef typename HeapConstants<heapType>::Block Block;
+ typedef typename HeapConstants<heapType>::Cell Cell;
+
+ Block** m_block;
+ Block** m_endBlock;
+ Cell* m_cell;
+ Cell* m_endCell;
};
- inline CollectorHeapIterator::CollectorHeapIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
- : m_heap(heap)
- , m_block(startBlock)
- , m_cell(startCell)
- {
- }
-
- inline bool CollectorHeapIterator::operator!=(const CollectorHeapIterator& other)
- {
- return m_block != other.m_block || m_cell != other.m_cell;
- }
-
- inline JSCell* CollectorHeapIterator::operator*() const
- {
- return reinterpret_cast<JSCell*>(m_heap.blocks[m_block]->cells + m_cell);
- }
-
- inline void CollectorHeapIterator::advance(size_t cellsPerBlock)
- {
- ++m_cell;
- if (m_cell == cellsPerBlock) {
- m_cell = 0;
- ++m_block;
- }
- }
-
- template <HeapType heapType>
- inline LiveObjectIterator<heapType>::LiveObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
- : CollectorHeapIterator(heap, startBlock, startCell - 1)
- {
- ++(*this);
- }
-
- template <HeapType heapType>
- inline LiveObjectIterator<heapType>& LiveObjectIterator<heapType>::operator++()
- {
- if (m_block < m_heap.nextBlock || m_cell < m_heap.nextCell) {
- advance(HeapConstants<heapType>::cellsPerBlock);
- return *this;
- }
-
- do {
- advance(HeapConstants<heapType>::cellsPerBlock);
- } while (m_block < m_heap.usedBlocks && !m_heap.blocks[m_block]->marked.get(m_cell));
- return *this;
- }
-
- template <HeapType heapType>
- inline DeadObjectIterator<heapType>::DeadObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
- : CollectorHeapIterator(heap, startBlock, startCell - 1)
+ template <HeapType heapType>
+ CollectorHeapIterator<heapType>::CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock)
+ : m_block(reinterpret_cast<Block**>(block))
+ , m_endBlock(reinterpret_cast<Block**>(endBlock))
+ , m_cell(m_block == m_endBlock ? 0 : (*m_block)->cells)
+ , m_endCell(m_block == m_endBlock ? 0 : (*m_block)->cells + HeapConstants<heapType>::cellsPerBlock)
{
- ++(*this);
+ if (m_cell && m_cell->u.freeCell.zeroIfFree == 0)
+ ++*this;
}
- template <HeapType heapType>
- inline DeadObjectIterator<heapType>& DeadObjectIterator<heapType>::operator++()
+ template <HeapType heapType>
+ CollectorHeapIterator<heapType>& CollectorHeapIterator<heapType>::operator++()
{
do {
- advance(HeapConstants<heapType>::cellsPerBlock);
- ASSERT(m_block > m_heap.nextBlock || (m_block == m_heap.nextBlock && m_cell >= m_heap.nextCell));
- } while (m_block < m_heap.usedBlocks && m_heap.blocks[m_block]->marked.get(m_cell));
+ for (++m_cell; m_cell != m_endCell; ++m_cell)
+ if (m_cell->u.freeCell.zeroIfFree != 0) {
+ return *this;
+ }
+
+ if (++m_block != m_endBlock) {
+ m_cell = (*m_block)->cells;
+ m_endCell = (*m_block)->cells + HeapConstants<heapType>::cellsPerBlock;
+ }
+ } while(m_block != m_endBlock);
+
+ m_cell = 0;
return *this;
}
- template <HeapType heapType>
- inline ObjectIterator<heapType>::ObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
- : CollectorHeapIterator(heap, startBlock, startCell - 1)
+ template <HeapType heapType>
+ JSCell* CollectorHeapIterator<heapType>::operator*() const
{
- ++(*this);
- }
-
- template <HeapType heapType>
- inline ObjectIterator<heapType>& ObjectIterator<heapType>::operator++()
- {
- advance(HeapConstants<heapType>::cellsPerBlock);
- return *this;
+ return reinterpret_cast<JSCell*>(m_cell);
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/JSArray.cpp b/JavaScriptCore/runtime/JSArray.cpp
index 0d2a9b4..b16d3fa 100644
--- a/JavaScriptCore/runtime/JSArray.cpp
+++ b/JavaScriptCore/runtime/JSArray.cpp
@@ -380,6 +380,8 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu
unsigned vectorLength = m_vectorLength;
+ Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
+
if (newNumValuesInVector == storage->m_numValuesInVector + 1) {
for (unsigned j = vectorLength; j < newVectorLength; ++j)
storage->m_vector[j] = JSValue();
@@ -400,8 +402,6 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu
m_storage = storage;
checkConsistency();
-
- Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
}
bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName)
@@ -492,15 +492,13 @@ bool JSArray::increaseVectorLength(unsigned newLength)
if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage))
return false;
+ Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
m_vectorLength = newVectorLength;
for (unsigned i = vectorLength; i < newVectorLength; ++i)
storage->m_vector[i] = JSValue();
m_storage = storage;
-
- Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
-
return true;
}
diff --git a/JavaScriptCore/runtime/JSCell.h b/JavaScriptCore/runtime/JSCell.h
index 5dfe206..c8ba2b8 100644
--- a/JavaScriptCore/runtime/JSCell.h
+++ b/JavaScriptCore/runtime/JSCell.h
@@ -47,18 +47,10 @@ namespace JSC {
private:
explicit JSCell(Structure*);
-
- // Only used for initializing Collector blocks.
- enum DummyDestructableCellTag { DummyDestructableCell };
- JSCell(DummyDestructableCellTag);
+ JSCell(); // Only used for initializing Collector blocks.
virtual ~JSCell();
public:
- static PassRefPtr<Structure> createDummyStructure()
- {
- return Structure::create(jsNull(), TypeInfo(UnspecifiedType));
- }
-
// Querying the type.
#if USE(JSVALUE32)
bool isNumber() const;
@@ -130,7 +122,8 @@ namespace JSC {
{
}
- inline JSCell::JSCell(DummyDestructableCellTag)
+ // Only used for initializing Collector blocks.
+ inline JSCell::JSCell()
{
}
diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp
index 7726f4d..234449f 100644
--- a/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -126,7 +126,6 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet)
, propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull()))
, getterSetterStructure(GetterSetter::createStructure(jsNull()))
, apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull()))
- , dummyMarkableCellStructure(JSCell::createDummyStructure())
#if USE(JSVALUE32)
, numberStructure(JSNumberCell::createStructure(jsNull()))
#endif
diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h
index 9f725c6..f0c1b5c 100644
--- a/JavaScriptCore/runtime/JSGlobalData.h
+++ b/JavaScriptCore/runtime/JSGlobalData.h
@@ -123,7 +123,6 @@ namespace JSC {
RefPtr<Structure> propertyNameIteratorStructure;
RefPtr<Structure> getterSetterStructure;
RefPtr<Structure> apiWrapperStructure;
- RefPtr<Structure> dummyMarkableCellStructure;
#if USE(JSVALUE32)
RefPtr<Structure> numberStructure;
diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h
index 81ec1d2..33e60ab 100644
--- a/JavaScriptCore/runtime/JSString.h
+++ b/JavaScriptCore/runtime/JSString.h
@@ -421,7 +421,7 @@ namespace JSC {
if (c <= 0xFF)
return globalData->smallStrings.singleCharacterString(globalData, c);
}
- return new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner);
+ return new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)));
}
inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s)
diff --git a/JavaScriptCore/runtime/Tracing.d b/JavaScriptCore/runtime/Tracing.d
index da854b9..b9efaff 100644
--- a/JavaScriptCore/runtime/Tracing.d
+++ b/JavaScriptCore/runtime/Tracing.d
@@ -27,7 +27,7 @@ provider JavaScriptCore
{
probe gc__begin();
probe gc__marked();
- probe gc__end();
+ probe gc__end(int, int);
probe profile__will_execute(int, char*, char*, int);
probe profile__did_execute(int, char*, char*, int);
diff --git a/JavaScriptCore/runtime/Tracing.h b/JavaScriptCore/runtime/Tracing.h
index c28c85f..e544f66 100644
--- a/JavaScriptCore/runtime/Tracing.h
+++ b/JavaScriptCore/runtime/Tracing.h
@@ -33,7 +33,7 @@
#define JAVASCRIPTCORE_GC_BEGIN()
#define JAVASCRIPTCORE_GC_BEGIN_ENABLED() 0
-#define JAVASCRIPTCORE_GC_END()
+#define JAVASCRIPTCORE_GC_END(arg0, arg1)
#define JAVASCRIPTCORE_GC_END_ENABLED() 0
#define JAVASCRIPTCORE_GC_MARKED()
diff --git a/JavaScriptCore/runtime/UString.h b/JavaScriptCore/runtime/UString.h
index a2a0e56..9c2433b 100644
--- a/JavaScriptCore/runtime/UString.h
+++ b/JavaScriptCore/runtime/UString.h
@@ -512,7 +512,7 @@ namespace JSC {
// huge buffer.
// FIXME: this should be size_t but that would cause warnings until we
// fix UString sizes to be size_t instead of int
- static const int minShareSize = Heap::minExtraCost / sizeof(UChar);
+ static const int minShareSize = Heap::minExtraCostSize / sizeof(UChar);
inline size_t UString::cost() const
{
diff --git a/JavaScriptCore/runtime/WeakGCMap.h b/JavaScriptCore/runtime/WeakGCMap.h
deleted file mode 100644
index 9d5f8c7..0000000
--- a/JavaScriptCore/runtime/WeakGCMap.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WeakGCMap_h
-#define WeakGCMap_h
-
-#include <wtf/HashMap.h>
-
-namespace JSC {
-
-class JSCell;
-
-// A HashMap whose get() function returns emptyValue() for cells awaiting destruction.
-template<typename KeyType, typename MappedType>
-class WeakGCMap {
- /*
- Invariants:
- * A value enters the WeakGCMap marked. (Guaranteed by set()).
- * A value that becomes unmarked leaves the WeakGCMap before being recycled. (Guaranteed by the value's destructor removing it from the WeakGCMap.)
- * A value that becomes unmarked leaves the WeakGCMap before becoming marked again. (Guaranteed by all destructors running before the mark phase begins.)
- * During the mark phase, all values in the WeakGCMap are valid. (Guaranteed by all destructors running before the mark phase begins.)
- */
-
-public:
- typedef typename HashMap<KeyType, MappedType>::iterator iterator;
- typedef typename HashMap<KeyType, MappedType>::const_iterator const_iterator;
-
- bool isEmpty() { return m_map.isEmpty(); }
-
- MappedType get(const KeyType& key) const;
- pair<iterator, bool> set(const KeyType&, const MappedType&);
- MappedType take(const KeyType& key);
-
- // These unchecked functions provide access to a value even if the value's
- // mark bit is not set. This is used, among other things, to retrieve values
- // during the GC mark phase, which begins by clearing all mark bits.
-
- MappedType uncheckedGet(const KeyType& key) const { return m_map.get(key); }
- bool uncheckedRemove(const KeyType&, const MappedType&);
-
- iterator uncheckedBegin() { return m_map.begin(); }
- iterator uncheckedEnd() { return m_map.end(); }
-
- const_iterator uncheckedBegin() const { return m_map.begin(); }
- const_iterator uncheckedEnd() const { return m_map.end(); }
-
-private:
- HashMap<KeyType, MappedType> m_map;
-};
-
-template<typename KeyType, typename MappedType>
-MappedType WeakGCMap<KeyType, MappedType>::get(const KeyType& key) const
-{
- MappedType result = m_map.get(key);
- if (!Heap::isCellMarked(result))
- return HashTraits<MappedType>::emptyValue();
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-MappedType WeakGCMap<KeyType, MappedType>::take(const KeyType& key)
-{
- MappedType result = m_map.take(key);
- if (!Heap::isCellMarked(result))
- return HashTraits<MappedType>::emptyValue();
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-pair<typename HashMap<KeyType, MappedType>::iterator, bool> WeakGCMap<KeyType, MappedType>::set(const KeyType& key, const MappedType& value)
-{
- Heap::markCell(value); // If value is newly allocated, it's not marked, so mark it now.
- pair<iterator, bool> result = m_map.add(key, value);
- if (!result.second) { // pre-existing entry
- result.second = !Heap::isCellMarked(result.first->second);
- result.first->second = value;
- }
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-bool WeakGCMap<KeyType, MappedType>::uncheckedRemove(const KeyType& key, const MappedType& value)
-{
- iterator it = m_map.find(key);
- if (it == m_map.end())
- return false;
- if (it->second != value)
- return false;
- m_map.remove(it);
- return true;
-}
-
-} // namespace JSC
-
-#endif // WeakGCMap_h
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WeakGCMap_h
-#define WeakGCMap_h
-
-#include <wtf/HashMap.h>
-
-namespace JSC {
-
-class JSCell;
-
-// A HashMap whose get() function returns emptyValue() for cells awaiting destruction.
-template<typename KeyType, typename MappedType>
-class WeakGCMap {
- /*
- Invariants:
- * A value enters the WeakGCMap marked. (Guaranteed by set()).
- * A value that becomes unmarked leaves the WeakGCMap before being recycled. (Guaranteed by the value's destructor removing it from the WeakGCMap.)
- * A value that becomes unmarked leaves the WeakGCMap before becoming marked again. (Guaranteed by all destructors running before the mark phase begins.)
- * During the mark phase, all values in the WeakGCMap are valid. (Guaranteed by all destructors running before the mark phase begins.)
- */
-
-public:
- typedef typename HashMap<KeyType, MappedType>::iterator iterator;
- typedef typename HashMap<KeyType, MappedType>::const_iterator const_iterator;
-
- bool isEmpty() { return m_map.isEmpty(); }
-
- MappedType get(const KeyType& key) const;
- pair<iterator, bool> set(const KeyType&, const MappedType&);
- MappedType take(const KeyType& key);
-
- // These unchecked functions provide access to a value even if the value's
- // mark bit is not set. This is used, among other things, to retrieve values
- // during the GC mark phase, which begins by clearing all mark bits.
-
- MappedType uncheckedGet(const KeyType& key) const { return m_map.get(key); }
- bool uncheckedRemove(const KeyType&, const MappedType&);
-
- iterator uncheckedBegin() { return m_map.begin(); }
- iterator uncheckedEnd() { return m_map.end(); }
-
- const_iterator uncheckedBegin() const { return m_map.begin(); }
- const_iterator uncheckedEnd() const { return m_map.end(); }
-
-private:
- HashMap<KeyType, MappedType> m_map;
-};
-
-template<typename KeyType, typename MappedType>
-MappedType WeakGCMap<KeyType, MappedType>::get(const KeyType& key) const
-{
- MappedType result = m_map.get(key);
- if (!Heap::isCellMarked(result))
- return HashTraits<MappedType>::emptyValue();
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-MappedType WeakGCMap<KeyType, MappedType>::take(const KeyType& key)
-{
- MappedType result = m_map.take(key);
- if (!Heap::isCellMarked(result))
- return HashTraits<MappedType>::emptyValue();
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-pair<typename HashMap<KeyType, MappedType>::iterator, bool> WeakGCMap<KeyType, MappedType>::set(const KeyType& key, const MappedType& value)
-{
- Heap::markCell(value); // If value is newly allocated, it's not marked, so mark it now.
- pair<iterator, bool> result = m_map.add(key, value);
- if (!result.second) { // pre-existing entry
- result.second = !Heap::isCellMarked(result.first->second);
- result.first->second = value;
- }
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-bool WeakGCMap<KeyType, MappedType>::uncheckedRemove(const KeyType& key, const MappedType& value)
-{
- iterator it = m_map.find(key);
- if (it == m_map.end())
- return false;
- if (it->second != value)
- return false;
- m_map.remove(it);
- return true;
-}
-
-} // namespace JSC
-
-#endif // WeakGCMap_h
diff --git a/JavaScriptCore/wtf/StdLibExtras.h b/JavaScriptCore/wtf/StdLibExtras.h
index 09436ab..dd90c85 100644
--- a/JavaScriptCore/wtf/StdLibExtras.h
+++ b/JavaScriptCore/wtf/StdLibExtras.h
@@ -69,14 +69,6 @@ namespace WTF {
return u.to;
}
- // Returns a count of the number of bits set in 'bits'.
- inline size_t bitCount(unsigned bits)
- {
- bits = bits - ((bits >> 1) & 0x55555555);
- bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
- return ((bits + (bits >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
- }
-
} // namespace WTF
#endif
diff --git a/JavaScriptGlue/ChangeLog b/JavaScriptGlue/ChangeLog
index d786c6d..95cce28 100644
--- a/JavaScriptGlue/ChangeLog
+++ b/JavaScriptGlue/ChangeLog
@@ -1,13 +1,3 @@
-2009-12-11 Geoffrey Garen <ggaren at apple.com>
-
- Reviewed by Sam Weinig.
-
- Changed GC from mark-sweep to mark-allocate.
-
- * JavaScriptGlue.cpp:
- (JSCollect): Updated for rename. Fixed a bug where JSGlue would not check
- to avoid nested GC calls.
-
2009-12-08 Dmitry Titov <dimich at chromium.org>
Rubber-stamped by David Levin.
diff --git a/JavaScriptGlue/JavaScriptGlue.cpp b/JavaScriptGlue/JavaScriptGlue.cpp
index e552f19..b4f26e9 100644
--- a/JavaScriptGlue/JavaScriptGlue.cpp
+++ b/JavaScriptGlue/JavaScriptGlue.cpp
@@ -339,9 +339,7 @@ void JSCollect()
initializeThreading();
JSLock lock(LockForReal);
- Heap* heap = getThreadGlobalExecState()->heap();
- if (!heap->isBusy())
- heap->collectAllGarbage();
+ getThreadGlobalExecState()->heap()->collect();
}
/*
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 514cd45..22fcd0f 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,9 +1,3 @@
-2009-12-11 Geoffrey Garen <ggaren at apple.com>
-
- Windows build fix: Removed an incorrect #ifdef.
-
- * bindings/js/GCController.cpp:
-
2009-12-11 Eric Roman <eroman at chromium.org>
Unreviewed build fix.
@@ -14,62 +8,6 @@
(WebCore::ScriptController::anyPageIsProcessingUserGesture):
* bindings/v8/ScriptController.h:
-2009-12-11 Geoffrey Garen <ggaren at apple.com>
-
- Reviewed by Sam Weinig.
-
- Changed GC from mark-sweep to mark-allocate.
-
- * ForwardingHeaders/runtime/WeakGCMap.h: Added.
- * bindings/js/GCController.cpp:
- (WebCore::collect):
- (WebCore::GCController::gcTimerFired):
- (WebCore::GCController::garbageCollectNow): Updated for rename.
-
- * bindings/js/JSDOMBinding.cpp:
- (WebCore::removeWrappers):
- (WebCore::hasCachedDOMObjectWrapperUnchecked):
- (WebCore::hasCachedDOMObjectWrapper):
- (WebCore::hasCachedDOMNodeWrapperUnchecked):
- (WebCore::forgetDOMObject):
- (WebCore::forgetDOMNode):
- (WebCore::isObservableThroughDOM):
- (WebCore::markDOMNodesForDocument):
- (WebCore::markDOMObjectWrapper):
- (WebCore::markDOMNodeWrapper):
- * bindings/js/JSDOMBinding.h: Changed DOM wrapper maps to be WeakGCMaps.
- Don't ASSERT that an item must be in the WeakGCMap when its destructor
- runs, since it might have been overwritten in the map first.
-
- * bindings/js/JSDocumentCustom.cpp:
- (WebCore::toJS): Changed Document from a DOM object wrapper to a DOM node
- wrapper, to simplify some code.
-
- * bindings/js/JSInspectedObjectWrapper.cpp:
- (WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
- (WebCore::JSInspectedObjectWrapper::~JSInspectedObjectWrapper):
- * bindings/js/JSInspectorCallbackWrapper.cpp: Use a WeakGCMap for these
- wrappers.
-
- * bindings/js/JSNodeCustom.cpp:
- (WebCore::JSNode::markChildren): Updated for WeakGCMap and Document using
- a DOM node wrapper instead of a DOM object wrapper.
-
- * bindings/js/JSSVGPODTypeWrapper.h:
- (WebCore::JSSVGDynamicPODTypeWrapperCache::wrapperMap):
- (WebCore::JSSVGDynamicPODTypeWrapperCache::lookupOrCreateWrapper):
- (WebCore::JSSVGDynamicPODTypeWrapperCache::forgetWrapper):
- (WebCore::::~JSSVGDynamicPODTypeWrapper): Shined a small beam of sanity
- on this code. Use hashtable-based lookup in JSSVGPODTypeWrapper.h instead
- of linear lookup through iteration, since that's what hashtables were
- invented for. Make JSSVGPODTypeWrapper.h responsible for reomving itself
- from the table, instead of its JS wrapper, to decouple these objects from
- GC, and because these objects are refCounted, not solely owned by their
- JS wrappers.
-
- * bindings/scripts/CodeGeneratorJS.pm:
- * dom/Document.h: Adopted changes above.
-
2009-12-11 Dimitri Glazkov <dglazkov at chromium.org>
Unreviewed, build fix.
diff --git a/WebCore/ForwardingHeaders/runtime/WeakGCMap.h b/WebCore/ForwardingHeaders/runtime/WeakGCMap.h
deleted file mode 100644
index 89432a8..0000000
--- a/WebCore/ForwardingHeaders/runtime/WeakGCMap.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef WebCore_FWD_WeakGCMap_h
-#define WebCore_FWD_WeakGCMap_h
-#include <JavaScriptCore/WeakGCMap.h>
-#endif
diff --git a/WebCore/bindings/js/GCController.cpp b/WebCore/bindings/js/GCController.cpp
index 3e5645f..59bcfa3 100644
--- a/WebCore/bindings/js/GCController.cpp
+++ b/WebCore/bindings/js/GCController.cpp
@@ -40,13 +40,17 @@ using namespace JSC;
namespace WebCore {
+#if USE(PTHREADS)
+
static void* collect(void*)
{
JSLock lock(SilenceAssertionsOnly);
- JSDOMWindow::commonJSGlobalData()->heap.collectAllGarbage();
+ JSDOMWindow::commonJSGlobalData()->heap.collect();
return 0;
}
+#endif
+
GCController& gcController()
{
DEFINE_STATIC_LOCAL(GCController, staticGCController, ());
@@ -66,12 +70,14 @@ void GCController::garbageCollectSoon()
void GCController::gcTimerFired(Timer<GCController>*)
{
- collect(0);
+ JSLock lock(SilenceAssertionsOnly);
+ JSDOMWindow::commonJSGlobalData()->heap.collect();
}
void GCController::garbageCollectNow()
{
- collect(0);
+ JSLock lock(SilenceAssertionsOnly);
+ JSDOMWindow::commonJSGlobalData()->heap.collect();
}
void GCController::garbageCollectOnAlternateThreadForDebugging(bool waitUntilDone)
diff --git a/WebCore/bindings/js/JSDOMBinding.cpp b/WebCore/bindings/js/JSDOMBinding.cpp
index 6faea27..f12c779 100644
--- a/WebCore/bindings/js/JSDOMBinding.cpp
+++ b/WebCore/bindings/js/JSDOMBinding.cpp
@@ -134,15 +134,15 @@ static void removeWrapper(DOMObject* wrapper)
static void removeWrappers(const JSWrapperCache& wrappers)
{
- JSWrapperCache::const_iterator wrappersEnd = wrappers.uncheckedEnd();
- for (JSWrapperCache::const_iterator it = wrappers.uncheckedBegin(); it != wrappersEnd; ++it)
+ JSWrapperCache::const_iterator wrappersEnd = wrappers.end();
+ for (JSWrapperCache::const_iterator it = wrappers.begin(); it != wrappersEnd; ++it)
removeWrapper(it->second);
}
static inline void removeWrappers(const DOMObjectWrapperMap& wrappers)
{
- DOMObjectWrapperMap::const_iterator wrappersEnd = wrappers.uncheckedEnd();
- for (DOMObjectWrapperMap::const_iterator it = wrappers.uncheckedBegin(); it != wrappersEnd; ++it)
+ DOMObjectWrapperMap::const_iterator wrappersEnd = wrappers.end();
+ for (DOMObjectWrapperMap::const_iterator it = wrappers.begin(); it != wrappersEnd; ++it)
removeWrapper(it->second);
}
@@ -242,19 +242,10 @@ static inline DOMObjectWrapperMap& DOMObjectWrapperMapFor(JSC::ExecState* exec)
return currentWorld(exec)->m_wrappers;
}
-bool hasCachedDOMObjectWrapperUnchecked(JSGlobalData* globalData, void* objectHandle)
-{
- for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
- if (worldIter->m_wrappers.uncheckedGet(objectHandle))
- return true;
- }
- return false;
-}
-
bool hasCachedDOMObjectWrapper(JSGlobalData* globalData, void* objectHandle)
{
for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
- if (worldIter->m_wrappers.get(objectHandle))
+ if (worldIter->m_wrappers.contains(objectHandle))
return true;
}
return false;
@@ -271,14 +262,14 @@ void cacheDOMObjectWrapper(JSC::ExecState* exec, void* objectHandle, DOMObject*
DOMObjectWrapperMapFor(exec).set(objectHandle, wrapper);
}
-bool hasCachedDOMNodeWrapperUnchecked(Document* document, Node* node)
+bool hasCachedDOMNodeWrapper(Document* document, Node* node)
{
if (!document)
- return hasCachedDOMObjectWrapperUnchecked(JSDOMWindow::commonJSGlobalData(), node);
+ return hasCachedDOMObjectWrapper(JSDOMWindow::commonJSGlobalData(), node);
JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
- if (iter->second->uncheckedGet(node))
+ if (iter->second->contains(node))
return true;
}
return false;
@@ -295,13 +286,20 @@ void forgetDOMObject(DOMObject* wrapper, void* objectHandle)
{
JSC::JSGlobalData* globalData = Heap::heap(wrapper)->globalData();
for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
- if (worldIter->m_wrappers.uncheckedRemove(objectHandle, wrapper))
- break;
+ DOMObjectWrapperMap& wrappers = worldIter->m_wrappers;
+ DOMObjectWrapperMap::iterator iter = wrappers.find(objectHandle);
+ if ((iter != wrappers.end()) && (iter->second == wrapper)) {
+ removeWrapper(wrapper);
+ wrappers.remove(iter);
+ return;
+ }
}
- removeWrapper(wrapper);
+
+ // If the world went away, it should have removed this wrapper from the set.
+ ASSERT(!wrapperSet().contains(wrapper));
}
-void forgetDOMNode(JSNode* wrapper, Node* node, Document* document)
+void forgetDOMNode(DOMObject* wrapper, Node* node, Document* document)
{
if (!document) {
forgetDOMObject(wrapper, node);
@@ -310,10 +308,17 @@ void forgetDOMNode(JSNode* wrapper, Node* node, Document* document)
JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
for (JSWrapperCacheMap::iterator wrappersIter = wrapperCacheMap.begin(); wrappersIter != wrapperCacheMap.end(); ++wrappersIter) {
- if (wrappersIter->second->uncheckedRemove(node, wrapper))
- break;
+ JSWrapperCache* wrappers = wrappersIter->second;
+ JSWrapperCache::iterator iter = wrappers->find(node);
+ if ((iter != wrappers->end()) && (iter->second == wrapper)) {
+ wrappers->remove(iter);
+ removeWrapper(wrapper);
+ return;
+ }
}
- removeWrapper(wrapper);
+
+ // If the world went away, it should have removed this wrapper from the set.
+ ASSERT(!wrapperSet().contains(wrapper));
}
void cacheDOMNodeWrapper(JSC::ExecState* exec, Document* document, Node* node, JSNode* wrapper)
@@ -374,14 +379,14 @@ static inline bool isObservableThroughDOM(JSNode* jsNode, DOMWrapperWorld* world
// the custom markChildren functions rather than here.
if (node->isElementNode()) {
if (NamedNodeMap* attributes = static_cast<Element*>(node)->attributeMap()) {
- if (DOMObject* wrapper = world->m_wrappers.uncheckedGet(attributes)) {
+ if (DOMObject* wrapper = world->m_wrappers.get(attributes)) {
if (wrapper->hasCustomProperties())
return true;
}
}
if (node->isStyledElement()) {
if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) {
- if (DOMObject* wrapper = world->m_wrappers.uncheckedGet(style)) {
+ if (DOMObject* wrapper = world->m_wrappers.get(style)) {
if (wrapper->hasCustomProperties())
return true;
}
@@ -389,7 +394,7 @@ static inline bool isObservableThroughDOM(JSNode* jsNode, DOMWrapperWorld* world
}
if (static_cast<Element*>(node)->hasTagName(canvasTag)) {
if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) {
- if (DOMObject* wrapper = world->m_wrappers.uncheckedGet(context)) {
+ if (DOMObject* wrapper = world->m_wrappers.get(context)) {
if (wrapper->hasCustomProperties())
return true;
}
@@ -427,8 +432,8 @@ void markDOMNodesForDocument(MarkStack& markStack, Document* document)
DOMWrapperWorld* world = wrappersIter->first;
JSWrapperCache* nodeDict = wrappersIter->second;
- JSWrapperCache::iterator nodeEnd = nodeDict->uncheckedEnd();
- for (JSWrapperCache::iterator nodeIt = nodeDict->uncheckedBegin(); nodeIt != nodeEnd; ++nodeIt) {
+ JSWrapperCache::iterator nodeEnd = nodeDict->end();
+ for (JSWrapperCache::iterator nodeIt = nodeDict->begin(); nodeIt != nodeEnd; ++nodeIt) {
JSNode* jsNode = nodeIt->second;
if (isObservableThroughDOM(jsNode, world))
markStack.append(jsNode);
@@ -511,7 +516,7 @@ void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void*
return;
for (JSGlobalDataWorldIterator worldIter(&globalData); worldIter; ++worldIter) {
- if (DOMObject* wrapper = worldIter->m_wrappers.uncheckedGet(object))
+ if (DOMObject* wrapper = worldIter->m_wrappers.get(object))
markStack.append(wrapper);
}
}
@@ -521,14 +526,14 @@ void markDOMNodeWrapper(MarkStack& markStack, Document* document, Node* node)
if (document) {
JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
- if (JSNode* wrapper = iter->second->uncheckedGet(node))
+ if (JSNode* wrapper = iter->second->get(node))
markStack.append(wrapper);
}
return;
}
for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {
- if (DOMObject* wrapper = worldIter->m_wrappers.uncheckedGet(node))
+ if (DOMObject* wrapper = worldIter->m_wrappers.get(node))
markStack.append(wrapper);
}
}
diff --git a/WebCore/bindings/js/JSDOMBinding.h b/WebCore/bindings/js/JSDOMBinding.h
index d0b6762..3982dad 100644
--- a/WebCore/bindings/js/JSDOMBinding.h
+++ b/WebCore/bindings/js/JSDOMBinding.h
@@ -23,10 +23,9 @@
#define JSDOMBinding_h
#include "JSDOMGlobalObject.h"
-#include "Document.h"
+#include "Document.h" // For DOMConstructorWithDocument
#include <runtime/Completion.h>
#include <runtime/Lookup.h>
-#include <runtime/WeakGCMap.h>
#include <wtf/Noncopyable.h>
namespace JSC {
@@ -140,7 +139,7 @@ namespace WebCore {
}
};
- typedef JSC::WeakGCMap<void*, DOMObject*> DOMObjectWrapperMap;
+ typedef HashMap<void*, DOMObject*> DOMObjectWrapperMap;
class DOMWrapperWorld : public RefCounted<DOMWrapperWorld> {
public:
@@ -217,24 +216,22 @@ namespace WebCore {
DOMWrapperWorld m_normalWorld;
};
- DOMObject* getCachedDOMObjectWrapper(JSC::ExecState*, void* objectHandle);
bool hasCachedDOMObjectWrapper(JSC::JSGlobalData*, void* objectHandle);
+ DOMObject* getCachedDOMObjectWrapper(JSC::ExecState*, void* objectHandle);
void cacheDOMObjectWrapper(JSC::ExecState*, void* objectHandle, DOMObject* wrapper);
- void forgetDOMNode(JSNode* wrapper, Node* node, Document* document);
+ void forgetDOMNode(DOMObject* wrapper, Node* node, Document* document);
void forgetDOMObject(DOMObject* wrapper, void* objectHandle);
+ bool hasCachedDOMNodeWrapper(Document*, Node*);
JSNode* getCachedDOMNodeWrapper(JSC::ExecState*, Document*, Node*);
void cacheDOMNodeWrapper(JSC::ExecState*, Document*, Node*, JSNode* wrapper);
void forgetAllDOMNodesForDocument(Document*);
void forgetWorldOfDOMNodesForDocument(Document*, DOMWrapperWorld*);
void updateDOMNodeDocument(Node*, Document* oldDocument, Document* newDocument);
-
void markDOMNodesForDocument(JSC::MarkStack&, Document*);
void markActiveObjectsForContext(JSC::MarkStack&, JSC::JSGlobalData&, ScriptExecutionContext*);
void markDOMObjectWrapper(JSC::MarkStack&, JSC::JSGlobalData& globalData, void* object);
void markDOMNodeWrapper(JSC::MarkStack& markStack, Document* document, Node* node);
- bool hasCachedDOMObjectWrapperUnchecked(JSC::JSGlobalData*, void* objectHandle);
- bool hasCachedDOMNodeWrapperUnchecked(Document*, Node*);
JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, NonNullPassRefPtr<JSC::Structure>, const JSC::ClassInfo*);
diff --git a/WebCore/bindings/js/JSDocumentCustom.cpp b/WebCore/bindings/js/JSDocumentCustom.cpp
index 9366399..4aa6583 100644
--- a/WebCore/bindings/js/JSDocumentCustom.cpp
+++ b/WebCore/bindings/js/JSDocumentCustom.cpp
@@ -96,18 +96,18 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Document* documen
if (!document)
return jsNull();
- DOMObject* wrapper = getCachedDOMNodeWrapper(exec, document, document);
+ DOMObject* wrapper = getCachedDOMObjectWrapper(exec, document);
if (wrapper)
return wrapper;
if (document->isHTMLDocument())
- wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, HTMLDocument, document);
+ wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, HTMLDocument, document);
#if ENABLE(SVG)
else if (document->isSVGDocument())
- wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, SVGDocument, document);
+ wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, SVGDocument, document);
#endif
else
- wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Document, document);
+ wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, Document, document);
// Make sure the document is kept around by the window object, and works right with the
// back/forward cache.
diff --git a/WebCore/bindings/js/JSInspectedObjectWrapper.cpp b/WebCore/bindings/js/JSInspectedObjectWrapper.cpp
index 60213b3..13f59b7 100644
--- a/WebCore/bindings/js/JSInspectedObjectWrapper.cpp
+++ b/WebCore/bindings/js/JSInspectedObjectWrapper.cpp
@@ -30,7 +30,6 @@
#include "JSInspectorCallbackWrapper.h"
#include <runtime/JSGlobalObject.h>
-#include <runtime/WeakGCMap.h>
#include <wtf/StdLibExtras.h>
using namespace JSC;
@@ -39,7 +38,7 @@ namespace WebCore {
ASSERT_CLASS_FITS_IN_CELL(JSInspectedObjectWrapper);
-typedef WeakGCMap<JSObject*, JSInspectedObjectWrapper*> WrapperMap;
+typedef HashMap<JSObject*, JSInspectedObjectWrapper*> WrapperMap;
typedef HashMap<JSGlobalObject*, WrapperMap*> GlobalObjectWrapperMap;
static GlobalObjectWrapperMap& wrappers()
@@ -82,17 +81,17 @@ JSInspectedObjectWrapper::JSInspectedObjectWrapper(ExecState* unwrappedExec, JSO
wrappers().set(unwrappedGlobalObject(), wrapperMap);
}
- pair<WrapperMap::iterator, bool> result = wrapperMap->set(unwrappedObject, this);
- ASSERT(result.second);
- UNUSED_PARAM(result);
+ ASSERT(!wrapperMap->contains(unwrappedObject));
+ wrapperMap->set(unwrappedObject, this);
}
JSInspectedObjectWrapper::~JSInspectedObjectWrapper()
{
+ ASSERT(wrappers().contains(unwrappedGlobalObject()));
WrapperMap* wrapperMap = wrappers().get(unwrappedGlobalObject());
- ASSERT(wrapperMap);
- wrapperMap->uncheckedRemove(unwrappedObject(), this);
+ ASSERT(wrapperMap->contains(unwrappedObject()));
+ wrapperMap->remove(unwrappedObject());
if (wrapperMap->isEmpty()) {
wrappers().remove(unwrappedGlobalObject());
diff --git a/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp b/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp
index 3a73fda..ff4fbb9 100644
--- a/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp
+++ b/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp
@@ -29,7 +29,6 @@
#if ENABLE(INSPECTOR)
#include "JSInspectedObjectWrapper.h"
-#include <runtime/Protect.h>
#include <wtf/StdLibExtras.h>
using namespace JSC;
diff --git a/WebCore/bindings/js/JSNodeCustom.cpp b/WebCore/bindings/js/JSNodeCustom.cpp
index 737430e..f375ae5 100644
--- a/WebCore/bindings/js/JSNodeCustom.cpp
+++ b/WebCore/bindings/js/JSNodeCustom.cpp
@@ -144,7 +144,7 @@ void JSNode::markChildren(MarkStack& markStack)
// mark any other nodes.
if (node->inDocument()) {
if (Document* doc = node->ownerDocument())
- markDOMNodeWrapper(markStack, doc, doc);
+ markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), doc);
return;
}
@@ -154,7 +154,7 @@ void JSNode::markChildren(MarkStack& markStack)
Node* outermostNodeWithWrapper = node;
for (Node* current = m_impl.get(); current; current = current->parentNode()) {
root = current;
- if (hasCachedDOMNodeWrapperUnchecked(current->document(), current))
+ if (hasCachedDOMNodeWrapper(current->document(), current))
outermostNodeWithWrapper = current;
}
diff --git a/WebCore/bindings/js/JSSVGPODTypeWrapper.h b/WebCore/bindings/js/JSSVGPODTypeWrapper.h
index fea7a5f..51e4e9e 100644
--- a/WebCore/bindings/js/JSSVGPODTypeWrapper.h
+++ b/WebCore/bindings/js/JSSVGPODTypeWrapper.h
@@ -105,8 +105,6 @@ private:
ASSERT(m_setter);
}
- virtual ~JSSVGDynamicPODTypeWrapper();
-
// Update callbacks
RefPtr<PODTypeCreator> m_creator;
GetterMethod m_getter;
@@ -353,7 +351,6 @@ struct PODTypeWrapperCacheInfoTraits : WTF::GenericHashTraits<PODTypeWrapperCach
}
};
-// Used for dynamic read-write attributes
template<typename PODType, typename PODTypeCreator>
class JSSVGDynamicPODTypeWrapperCache {
public:
@@ -365,41 +362,49 @@ public:
typedef PODTypeWrapperCacheInfoTraits<PODType, PODTypeCreator> CacheInfoTraits;
typedef JSSVGPODTypeWrapper<PODType> WrapperBase;
- typedef JSSVGDynamicPODTypeWrapper<PODType, PODTypeCreator> Wrapper;
- typedef HashMap<CacheInfo, Wrapper*, CacheInfoHash, CacheInfoTraits> WrapperMap;
+ typedef JSSVGDynamicPODTypeWrapper<PODType, PODTypeCreator> DynamicWrapper;
+ typedef HashMap<CacheInfo, DynamicWrapper*, CacheInfoHash, CacheInfoTraits> DynamicWrapperHashMap;
+ typedef typename DynamicWrapperHashMap::const_iterator DynamicWrapperHashMapIterator;
- static WrapperMap& wrapperMap()
+ static DynamicWrapperHashMap& dynamicWrapperHashMap()
{
- DEFINE_STATIC_LOCAL(WrapperMap, s_wrapperMap, ());
- return s_wrapperMap;
+ DEFINE_STATIC_LOCAL(DynamicWrapperHashMap, s_dynamicWrapperHashMap, ());
+ return s_dynamicWrapperHashMap;
}
+ // Used for readwrite attributes only
static PassRefPtr<WrapperBase> lookupOrCreateWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter)
{
+ DynamicWrapperHashMap& map(dynamicWrapperHashMap());
CacheInfo info(creator, getter, setter);
- pair<typename WrapperMap::iterator, bool> result = wrapperMap().add(info, 0);
- if (!result.second) // pre-existing entry
- return result.first->second;
- RefPtr<Wrapper> wrapper = Wrapper::create(creator, getter, setter);
- result.first->second = wrapper.get();
+ if (map.contains(info))
+ return map.get(info);
+
+ RefPtr<DynamicWrapper> wrapper = DynamicWrapper::create(creator, getter, setter);
+ map.set(info, wrapper.get());
return wrapper.release();
}
- static void forgetWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter)
+ static void forgetWrapper(WrapperBase* wrapper)
{
- CacheInfo info(creator, getter, setter);
- wrapperMap().remove(info);
+ DynamicWrapperHashMap& map(dynamicWrapperHashMap());
+
+ DynamicWrapperHashMapIterator it = map.begin();
+ DynamicWrapperHashMapIterator end = map.end();
+
+ for (; it != end; ++it) {
+ if (it->second != wrapper)
+ continue;
+
+ // It's guaranteed that there's just one object we need to take care of.
+ map.remove(it->first);
+ break;
+ }
}
};
-template<typename PODType, typename PODTypeCreator>
-JSSVGDynamicPODTypeWrapper<PODType, PODTypeCreator>::~JSSVGDynamicPODTypeWrapper()
-{
- JSSVGDynamicPODTypeWrapperCache<PODType, PODTypeCreator>::forgetWrapper(m_creator.get(), m_getter, m_setter);
-}
-
-} // namespace WebCore
+};
#endif // ENABLE(SVG)
#endif // JSSVGPODTypeWrapper_h
diff --git a/WebCore/bindings/scripts/CodeGeneratorJS.pm b/WebCore/bindings/scripts/CodeGeneratorJS.pm
index ca4b03c..6ccf739 100644
--- a/WebCore/bindings/scripts/CodeGeneratorJS.pm
+++ b/WebCore/bindings/scripts/CodeGeneratorJS.pm
@@ -566,7 +566,7 @@ sub GenerateHeader
}
# Destructor
- push(@headerContent, " virtual ~$className();\n") if (!$hasParent or $eventTarget or $interfaceName eq "DOMWindow");
+ push(@headerContent, " virtual ~$className();\n") if (!$hasParent or $eventTarget or $interfaceName eq "Document" or $interfaceName eq "DOMWindow");
# Prototype
push(@headerContent, " static JSC::JSObject* createPrototype(JSC::ExecState*, JSC::JSGlobalObject*);\n") unless ($dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"});
@@ -1210,6 +1210,15 @@ sub GenerateImplementation
if ($interfaceName eq "Node") {
push(@implContent, " forgetDOMNode(this, impl(), impl()->document());\n");
} else {
+ if ($podType) {
+ my $animatedType = $implClassName;
+ $animatedType =~ s/SVG/SVGAnimated/;
+
+ # Special case for JSSVGNumber
+ if ($codeGenerator->IsSVGAnimatedType($animatedType) and $podType ne "float") {
+ push(@implContent, " JSSVGDynamicPODTypeWrapperCache<$podType, $animatedType>::forgetWrapper(m_impl.get());\n");
+ }
+ }
push(@implContent, " forgetDOMObject(this, impl());\n");
}
}
@@ -1217,6 +1226,13 @@ sub GenerateImplementation
push(@implContent, "}\n\n");
}
+ # Document needs a special destructor because it's a special case for caching. It needs
+ # its own special handling rather than relying on the caching that Node normally does.
+ if ($interfaceName eq "Document") {
+ push(@implContent, "${className}::~$className()\n");
+ push(@implContent, "{\n forgetDOMObject(this, static_cast<${implClassName}*>(impl()));\n}\n\n");
+ }
+
if ($needsMarkChildren && !$dataNode->extendedAttributes->{"CustomMarkFunction"}) {
push(@implContent, "void ${className}::markChildren(MarkStack& markStack)\n");
push(@implContent, "{\n");
diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h
index 7e8c5bd..0f108e9 100644
--- a/WebCore/dom/Document.h
+++ b/WebCore/dom/Document.h
@@ -35,7 +35,6 @@
#include "DocumentMarker.h"
#include "ScriptExecutionContext.h"
#include "Timer.h"
-#include <runtime/WeakGCMap.h>
#include <wtf/HashCountedSet.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
@@ -830,7 +829,7 @@ public:
virtual void scriptImported(unsigned long, const String&);
virtual void postTask(PassOwnPtr<Task>); // Executes the task on context's thread asynchronously.
- typedef JSC::WeakGCMap<WebCore::Node*, JSNode*> JSWrapperCache;
+ typedef HashMap<WebCore::Node*, JSNode*> JSWrapperCache;
typedef HashMap<DOMWrapperWorld*, JSWrapperCache*> JSWrapperCacheMap;
JSWrapperCacheMap& wrapperCacheMap() { return m_wrapperCacheMap; }
JSWrapperCache* getWrapperCache(DOMWrapperWorld* world)
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list