Reviewed by Maciej.
Make JSGlobalData per-thread.
No change on SunSpider total.
* wtf/ThreadSpecific.h: Re-enabled the actual implementation.
* kjs/JSGlobalObject.cpp:
(KJS::JSGlobalObject::~JSGlobalObject): Re-added a JSLock-related assertion. We'll probably
want to preserve these somehow to keep legacy behavior in working condition.
(KJS::JSGlobalObject::init): Initialize globalData pointer earlier, so that it is ready
when updating JSGlobalObject linked list.
* kjs/JSGlobalObject.h: (KJS::JSGlobalObject::head): Changed head() to be non-static, and
to use JSGlobalData associated with the current object.
* kjs/InitializeThreading.cpp: (KJS::initializeThreadingOnce): Removed a no longer needed
Heap::registerAsMainThread() call.
* kjs/JSGlobalData.h: Removed a lying lie comment - parserObjectExtraRefCounts is not
transient, and while newParserObjects may conceptually be such, there is still some node
manipulation going on outside Parser::parse which touches it.
* kjs/JSGlobalData.cpp:
(KJS::JSGlobalData::~JSGlobalData): Delete recently added members.
(KJS::JSGlobalData::sharedInstance): Actually use a separate instance.
* kjs/collector.cpp:
(KJS::Heap::Heap):
(KJS::Heap::~Heap): Added a destructor, which unconditionally deletes everything.
(KJS::Heap::sweep): Removed code related to "collect on main thread only" logic.
(KJS::Heap::collect): Ditto.
(KJS::Heap::globalObjectCount): Explicitly use per-thread instance of JSGlobalObject linked
list now that JSGlobalObject::head() is not static. Curently, WebCoreStatistics methods only
work with the main thread currently anyway.
(KJS::Heap::protectedGlobalObjectCount): Ditto.
* kjs/collector.h: Removed code related to "collect on main thread only" logic.
* JavaScriptCore.exp: Removed Heap::collectOnMainThreadOnly.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@34810 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/kjs/InitializeThreading.cpp b/JavaScriptCore/kjs/InitializeThreading.cpp
index 177f0f6..ec0b2ce 100644
--- a/JavaScriptCore/kjs/InitializeThreading.cpp
+++ b/JavaScriptCore/kjs/InitializeThreading.cpp
@@ -48,9 +48,6 @@
WTF::initializeThreading();
#if USE(MULTIPLE_THREADS)
s_dtoaP5Mutex = new Mutex;
-#if !PLATFORM(DARWIN) // Darwin has pthread_main_np(), and doesn't need registerAsMainThread() called.
- Heap::registerAsMainThread();
-#endif
JSGlobalData::threadInstance();
UString::null();
initDateMath();
diff --git a/JavaScriptCore/kjs/JSGlobalData.cpp b/JavaScriptCore/kjs/JSGlobalData.cpp
index f3f951c..0b61d3d 100644
--- a/JavaScriptCore/kjs/JSGlobalData.cpp
+++ b/JavaScriptCore/kjs/JSGlobalData.cpp
@@ -89,6 +89,10 @@
JSGlobalData::~JSGlobalData()
{
#if USE(MULTIPLE_THREADS)
+ delete heap;
+
+ delete machine;
+
delete[] arrayTable->table;
delete[] dateTable->table;
delete[] mathTable->table;
@@ -109,6 +113,9 @@
delete propertyNames;
deleteIdentifierTable(identifierTable);
+
+ delete newParserObjects;
+ delete parserObjectExtraRefCounts;
#endif
}
@@ -125,15 +132,12 @@
JSGlobalData& JSGlobalData::sharedInstance()
{
- return threadInstance();
-/*
#if USE(MULTIPLE_THREADS)
AtomicallyInitializedStatic(JSGlobalData, sharedInstance);
#else
static JSGlobalData sharedInstance;
#endif
return sharedInstance;
-*/
}
}
diff --git a/JavaScriptCore/kjs/JSGlobalData.h b/JavaScriptCore/kjs/JSGlobalData.h
index 8f27123..6ced870 100644
--- a/JavaScriptCore/kjs/JSGlobalData.h
+++ b/JavaScriptCore/kjs/JSGlobalData.h
@@ -72,7 +72,6 @@
CommonIdentifiers* propertyNames;
const ArgList emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark.
- // Tracked object sets are transient, only needed when parsing.
HashSet<ParserRefCounted*>* newParserObjects;
HashCountedSet<ParserRefCounted*>* parserObjectExtraRefCounts;
diff --git a/JavaScriptCore/kjs/JSGlobalObject.cpp b/JavaScriptCore/kjs/JSGlobalObject.cpp
index 3077ca4..1971bb6 100644
--- a/JavaScriptCore/kjs/JSGlobalObject.cpp
+++ b/JavaScriptCore/kjs/JSGlobalObject.cpp
@@ -91,6 +91,8 @@
JSGlobalObject::~JSGlobalObject()
{
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
if (d()->debugger)
d()->debugger->detach(this);
@@ -113,6 +115,8 @@
{
ASSERT(JSLock::currentThreadIsHoldingLock());
+ d()->globalData = (Heap::heap(this) == JSGlobalData::sharedInstance().heap) ? &JSGlobalData::sharedInstance() : &JSGlobalData::threadInstance();
+
if (JSGlobalObject*& headObject = head()) {
d()->prev = headObject;
d()->next = headObject->d()->next;
@@ -128,8 +132,6 @@
d()->recursion = 0;
d()->debugger = 0;
- d()->globalData = (Heap::heap(this) == JSGlobalData::sharedInstance().heap) ? &JSGlobalData::sharedInstance() : &JSGlobalData::threadInstance();
-
d()->globalExec.set(new ExecState(this, thisValue, d()->globalScopeChain.node()));
d()->pageGroupIdentifier = 0;
diff --git a/JavaScriptCore/kjs/JSGlobalObject.h b/JavaScriptCore/kjs/JSGlobalObject.h
index 7eb83b9..5915cdf 100644
--- a/JavaScriptCore/kjs/JSGlobalObject.h
+++ b/JavaScriptCore/kjs/JSGlobalObject.h
@@ -161,7 +161,7 @@
virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc);
// Per-thread linked list of all global objects.
- static JSGlobalObject*& head() { return JSGlobalData::threadInstance().head; }
+ JSGlobalObject*& head() { return d()->globalData->head; }
JSGlobalObject* next() { return d()->next; }
// Resets the global object to contain only built-in properties, sets
diff --git a/JavaScriptCore/kjs/collector.cpp b/JavaScriptCore/kjs/collector.cpp
index 206266d..152d43c 100644
--- a/JavaScriptCore/kjs/collector.cpp
+++ b/JavaScriptCore/kjs/collector.cpp
@@ -87,14 +87,29 @@
// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
#define MIN_ARRAY_SIZE (static_cast<size_t>(14))
+static void freeHeap(CollectorHeap*);
+
Heap::Heap()
- : mainThreadOnlyObjectCount(0)
- , m_markListSet(0)
+ : m_markListSet(0)
{
memset(&primaryHeap, 0, sizeof(CollectorHeap));
memset(&numberHeap, 0, sizeof(CollectorHeap));
}
+Heap::~Heap()
+{
+ JSLock lock;
+
+ delete m_markListSet;
+ sweep<PrimaryHeap>();
+ // No need to sweep number heap, because the JSNumber destructor doesn't do anything.
+
+ ASSERT(!primaryHeap.numLiveObjects);
+
+ freeHeap(&primaryHeap);
+ freeHeap(&numberHeap);
+}
+
static NEVER_INLINE CollectorBlock* allocateBlock()
{
#if PLATFORM(DARWIN)
@@ -151,6 +166,15 @@
#endif
}
+static void freeHeap(CollectorHeap* heap)
+{
+ 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)
{
// Our frequency of garbage collection tries to balance memory use against speed
@@ -367,30 +391,6 @@
}
#if USE(MULTIPLE_THREADS)
-static pthread_t mainThread;
-#endif
-
-void Heap::registerAsMainThread()
-{
-#if USE(MULTIPLE_THREADS)
- mainThread = pthread_self();
-#endif
-}
-
-static inline bool onMainThread()
-{
-#if USE(MULTIPLE_THREADS)
-#if PLATFORM(DARWIN)
- return pthread_main_np();
-#else
- return !!pthread_equal(pthread_self(), mainThread);
-#endif
-#else
- return true;
-#endif
-}
-
-#if USE(MULTIPLE_THREADS)
#if PLATFORM(DARWIN)
typedef mach_port_t PlatformThread;
@@ -770,20 +770,6 @@
protectedValues.remove(k->asCell());
}
-void Heap::collectOnMainThreadOnly(JSValue* value)
-{
- ASSERT(value);
- ASSERT(JSLock::lockCount() > 0);
- ASSERT(JSLock::currentThreadIsHoldingLock());
-
- if (JSImmediate::isImmediate(value))
- return;
-
- JSCell* cell = value->asCell();
- cellBlock(cell)->collectOnMainThreadOnly.set(cellOffset(cell));
- ++mainThreadOnlyObjectCount;
-}
-
Heap* Heap::heap(const JSValue* v)
{
if (JSImmediate::isImmediate(v))
@@ -801,54 +787,11 @@
}
}
-void Heap::markMainThreadOnlyObjects()
-{
-#if USE(MULTIPLE_THREADS)
- ASSERT(!onMainThread());
-#endif
-
- // Optimization for clients that never register "main thread only" objects.
- if (!mainThreadOnlyObjectCount)
- return;
-
- // FIXME: We can optimize this marking algorithm by keeping an exact set of
- // "main thread only" objects when the "main thread only" object count is
- // small. We don't want to keep an exact set all the time, because WebCore
- // tends to create lots of "main thread only" objects, and all that set
- // thrashing can be expensive.
-
- size_t count = 0;
-
- // We don't look at the numberHeap as primitive values can never be marked as main thread only
- for (size_t block = 0; block < primaryHeap.usedBlocks; block++) {
- ASSERT(count < mainThreadOnlyObjectCount);
-
- CollectorBlock* curBlock = primaryHeap.blocks[block];
- size_t minimumCellsToProcess = curBlock->usedCells;
- for (size_t i = 0; (i < minimumCellsToProcess) & (i < CELLS_PER_BLOCK); i++) {
- CollectorCell* cell = curBlock->cells + i;
- if (cell->u.freeCell.zeroIfFree == 0)
- ++minimumCellsToProcess;
- else {
- if (curBlock->collectOnMainThreadOnly.get(i)) {
- if (!curBlock->marked.get(i)) {
- JSCell* imp = reinterpret_cast<JSCell*>(cell);
- imp->mark();
- }
- if (++count == mainThreadOnlyObjectCount)
- return;
- }
- }
- }
- }
-}
-
-template <Heap::HeapType heapType> size_t Heap::sweep(bool currentThreadIsMainThread)
+template <Heap::HeapType heapType> size_t Heap::sweep()
{
typedef typename HeapConstants<heapType>::Block Block;
typedef typename HeapConstants<heapType>::Cell Cell;
- UNUSED_PARAM(currentThreadIsMainThread); // currentThreadIsMainThread is only used in ASSERTs
// SWEEP: delete everything with a zero refcount (garbage) and unmark everything else
CollectorHeap& heap = heapType == Heap::PrimaryHeap ? primaryHeap : numberHeap;
@@ -875,11 +818,6 @@
if (cell->u.freeCell.zeroIfFree == 0)
continue;
- ASSERT(currentThreadIsMainThread || !curBlock->collectOnMainThreadOnly.get(i));
- if (curBlock->collectOnMainThreadOnly.get(i)) {
- curBlock->collectOnMainThreadOnly.clear(i);
- --mainThreadOnlyObjectCount;
- }
imp->~JSCell();
}
@@ -902,11 +840,6 @@
if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) {
if (heapType != Heap::NumberHeap) {
JSCell* imp = reinterpret_cast<JSCell*>(cell);
- ASSERT(currentThreadIsMainThread || !curBlock->collectOnMainThreadOnly.get(i));
- if (curBlock->collectOnMainThreadOnly.get(i)) {
- curBlock->collectOnMainThreadOnly.clear(i);
- --mainThreadOnlyObjectCount;
- }
imp->~JSCell();
}
--usedCells;
@@ -969,22 +902,16 @@
primaryHeap.operationInProgress = Collection;
numberHeap.operationInProgress = Collection;
- bool currentThreadIsMainThread = onMainThread();
-
// MARK: first mark all referenced objects recursively starting out from the set of root objects
markStackObjectsConservatively();
markProtectedObjects();
if (m_markListSet && m_markListSet->size())
ArgList::markLists(*m_markListSet);
-#if USE(MULTIPLE_THREADS)
- if (!currentThreadIsMainThread)
- markMainThreadOnlyObjects();
-#endif
size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
- size_t numLiveObjects = sweep<PrimaryHeap>(currentThreadIsMainThread);
- numLiveObjects += sweep<NumberHeap>(currentThreadIsMainThread);
+ size_t numLiveObjects = sweep<PrimaryHeap>();
+ numLiveObjects += sweep<NumberHeap>();
primaryHeap.operationInProgress = NoOperation;
numberHeap.operationInProgress = NoOperation;
@@ -1000,12 +927,12 @@
size_t Heap::globalObjectCount()
{
size_t count = 0;
- if (JSGlobalObject::head()) {
- JSGlobalObject* o = JSGlobalObject::head();
+ if (JSGlobalObject* head = JSGlobalData::threadInstance().head) {
+ JSGlobalObject* o = head;
do {
++count;
o = o->next();
- } while (o != JSGlobalObject::head());
+ } while (o != head);
}
return count;
}
@@ -1013,13 +940,13 @@
size_t Heap::protectedGlobalObjectCount()
{
size_t count = 0;
- if (JSGlobalObject::head()) {
- JSGlobalObject* o = JSGlobalObject::head();
+ if (JSGlobalObject* head = JSGlobalData::threadInstance().head) {
+ JSGlobalObject* o = head;
do {
if (protectedValues.contains(o))
++count;
o = o->next();
- } while (o != JSGlobalObject::head());
+ } while (o != head);
}
return count;
}
diff --git a/JavaScriptCore/kjs/collector.h b/JavaScriptCore/kjs/collector.h
index c30800b..bfdb373 100644
--- a/JavaScriptCore/kjs/collector.h
+++ b/JavaScriptCore/kjs/collector.h
@@ -77,8 +77,6 @@
void protect(JSValue*);
void unprotect(JSValue*);
- void collectOnMainThreadOnly(JSValue*);
-
static Heap* heap(const JSValue*); // 0 for immediate values
size_t globalObjectCount();
@@ -86,7 +84,6 @@
size_t protectedGlobalObjectCount();
HashCountedSet<const char*>* protectedObjectTypeCounts();
- static void registerAsMainThread();
static void registerThread(); // Should only be called by clients that can use the same heap from multiple threads.
#if PLATFORM(DARWIN) && USE(MULTIPLE_THREADS)
@@ -102,17 +99,17 @@
private:
template <Heap::HeapType heapType> void* heapAllocate(size_t);
- template <Heap::HeapType heapType> size_t sweep(bool);
+ template <Heap::HeapType heapType> size_t sweep();
static const CollectorBlock* cellBlock(const JSCell*);
static CollectorBlock* cellBlock(JSCell*);
static size_t cellOffset(const JSCell*);
Heap();
+ ~Heap();
friend class JSGlobalData;
void recordExtraCost(size_t);
void markProtectedObjects();
- void markMainThreadOnlyObjects();
void markCurrentThreadConservatively();
void markCurrentThreadConservativelyInternal();
void markOtherThreadConservatively(Thread*);
@@ -120,7 +117,6 @@
typedef HashCountedSet<JSCell*> ProtectCountSet;
- size_t mainThreadOnlyObjectCount;
CollectorHeap primaryHeap;
CollectorHeap numberHeap;
ProtectCountSet protectedValues;
@@ -183,7 +179,6 @@
uint32_t usedCells;
CollectorCell* freeList;
CollectorBitmap marked;
- CollectorBitmap collectOnMainThreadOnly;
Heap* heap;
};
@@ -193,7 +188,6 @@
uint32_t usedCells;
SmallCollectorCell* freeList;
CollectorBitmap marked;
- CollectorBitmap collectOnMainThreadOnly;
Heap* heap;
};