Commit 0b7e63be authored by ap@webkit.org's avatar ap@webkit.org

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
parent 66abd69a
2008-06-26 Alexey Proskuryakov <ap@webkit.org>
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.
2008-06-26 Alexey Proskuryakov <ap@webkit.org>
Reviewed by Darin.
......
......@@ -143,7 +143,6 @@ __ZN3KJS4Heap14allocateNumberEm
__ZN3KJS4Heap15recordExtraCostEm
__ZN3KJS4Heap17globalObjectCountEv
__ZN3KJS4Heap20protectedObjectCountEv
__ZN3KJS4Heap23collectOnMainThreadOnlyEPNS_7JSValueE
__ZN3KJS4Heap25protectedObjectTypeCountsEv
__ZN3KJS4Heap26protectedGlobalObjectCountEv
__ZN3KJS4Heap4heapEPKNS_7JSValueE
......
......@@ -48,9 +48,6 @@ static void initializeThreadingOnce()
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();
......
......@@ -89,6 +89,10 @@ JSGlobalData::JSGlobalData()
JSGlobalData::~JSGlobalData()
{
#if USE(MULTIPLE_THREADS)
delete heap;
delete machine;
delete[] arrayTable->table;
delete[] dateTable->table;
delete[] mathTable->table;
......@@ -109,6 +113,9 @@ JSGlobalData::~JSGlobalData()
delete propertyNames;
deleteIdentifierTable(identifierTable);
delete newParserObjects;
delete parserObjectExtraRefCounts;
#endif
}
......@@ -125,15 +132,12 @@ JSGlobalData& JSGlobalData::threadInstance()
JSGlobalData& JSGlobalData::sharedInstance()
{
return threadInstance();
/*
#if USE(MULTIPLE_THREADS)
AtomicallyInitializedStatic(JSGlobalData, sharedInstance);
#else
static JSGlobalData sharedInstance;
#endif
return sharedInstance;
*/
}
}
......@@ -72,7 +72,6 @@ namespace KJS {
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;
......
......@@ -91,6 +91,8 @@ static inline unsigned getCurrentTime()
JSGlobalObject::~JSGlobalObject()
{
ASSERT(JSLock::currentThreadIsHoldingLock());
if (d()->debugger)
d()->debugger->detach(this);
......@@ -113,6 +115,8 @@ void JSGlobalObject::init(JSObject* thisValue)
{
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 @@ void JSGlobalObject::init(JSObject* thisValue)
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;
......
......@@ -161,7 +161,7 @@ namespace KJS {
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
......
......@@ -87,14 +87,29 @@ const size_t ALLOCATIONS_PER_COLLECTION = 4000;
// 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 @@ static void freeBlock(CollectorBlock* block)
#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
......@@ -366,30 +390,6 @@ static inline void* currentThreadStackBase()
#endif
}
#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)
......@@ -770,20 +770,6 @@ void Heap::unprotect(JSValue* k)
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::markProtectedObjects()
}
}
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 @@ template <Heap::HeapType heapType> size_t Heap::sweep(bool currentThreadIsMainTh
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 @@ template <Heap::HeapType heapType> size_t Heap::sweep(bool currentThreadIsMainTh
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 @@ bool Heap::collect()
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::size()
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::globalObjectCount()
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;
}
......
......@@ -77,8 +77,6 @@ namespace KJS {
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 @@ namespace KJS {
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 @@ namespace KJS {
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 @@ namespace KJS {
typedef HashCountedSet<JSCell*> ProtectCountSet;
size_t mainThreadOnlyObjectCount;
CollectorHeap primaryHeap;
CollectorHeap numberHeap;
ProtectCountSet protectedValues;
......@@ -183,7 +179,6 @@ namespace KJS {
uint32_t usedCells;
CollectorCell* freeList;
CollectorBitmap marked;
CollectorBitmap collectOnMainThreadOnly;
Heap* heap;
};
......@@ -193,7 +188,6 @@ namespace KJS {
uint32_t usedCells;
SmallCollectorCell* freeList;
CollectorBitmap marked;
CollectorBitmap collectOnMainThreadOnly;
Heap* heap;
};
......
......@@ -52,7 +52,6 @@ private:
void set(T*);
void static destroy(void* ptr);
#if 0 // FIXME: Temporary disabled until the rest of multithreading support is in.
#if USE(PTHREADS) || PLATFORM(WIN)
struct Data : Noncopyable {
Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {}
......@@ -63,14 +62,8 @@ private:
pthread_key_t m_key;
#endif
#else // Temporary stub implementation.
T m_data;
#endif
};
#if 0 // FIXME: Temporary disabled until the rest of multithreading support is in.
#if USE(PTHREADS) || PLATFORM(WIN)
template<typename T>
inline ThreadSpecific<T>::ThreadSpecific()
......@@ -111,32 +104,6 @@ inline void ThreadSpecific<T>::destroy(void* ptr)
#error ThreadSpecific is not implemented for this platform.
#endif
#else // Temporary stub implementation.
template<typename T>
inline ThreadSpecific<T>::ThreadSpecific()
: m_data()
{
}
template<typename T>
inline ThreadSpecific<T>::~ThreadSpecific()
{
}
template<typename T>
inline T* ThreadSpecific<T>::get()
{
return &m_data;
}
template<typename T>
inline void ThreadSpecific<T>::set(T*)
{
}
#endif
template<typename T>
inline ThreadSpecific<T>::operator T*()
{
......
2008-06-26 Alexey Proskuryakov <ap@webkit.org>
Reviewed by Maciej.
Make JSGlobalData per-thread.
* bindings/js/JSDOMBinding.h:
(WebCore::DOMObject::DOMObject):
* bindings/js/JSDOMWindowBase.cpp:
(WebCore::JSDOMWindowBase::JSDOMWindowBase):
* bridge/runtime_object.cpp:
(RuntimeObjectImp::RuntimeObjectImp):
Removed collectOnMainThreadOnly() calls. WebCore objects live in their own heap now, so
there is no danger for them to be collected on a wrong thread.
2008-06-26 Holger Hans Peter Freyther <zecke@selfish.org>
Reviewed by Simon.
......@@ -49,9 +49,6 @@ namespace WebCore {
explicit DOMObject(KJS::JSValue* prototype) // FIXME: This could take a JSObject if JSDOMWindowShell had a prototype.
: JSObject(prototype)
{
// DOMObject destruction is not thread-safe because DOMObjects wrap
// unsafe WebCore DOM data structures.
KJS::Heap::heap(this)->collectOnMainThreadOnly(this);
}
#ifndef NDEBUG
......
......@@ -193,10 +193,6 @@ JSDOMWindowBase::JSDOMWindowBase(JSObject* prototype, DOMWindow* window, JSDOMWi
, m_impl(window)
, d(new JSDOMWindowBasePrivate(shell))
{
// JSDOMWindowBase destruction is not thread-safe because of
// the non-thread-safe WebCore structures it references.
Heap::heap(this)->collectOnMainThreadOnly(this);
// Time in milliseconds before the script timeout handler kicks in.
setTimeoutTime(10000);
......
......@@ -38,7 +38,6 @@ RuntimeObjectImp::RuntimeObjectImp(PassRefPtr<Bindings::Instance> i)
: instance(i)
{
instance->rootObject()->addRuntimeObject(this);
Heap::heap(this)->collectOnMainThreadOnly(this);
}
RuntimeObjectImp::~RuntimeObjectImp()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment