Ignore:
Timestamp:
Aug 10, 2009, 9:35:02 PM (16 years ago)
Author:
[email protected]
Message:

Stack overflow crash in JavaScript garbage collector mark pass
https://bugs.webkit.org/show_bug.cgi?id=12216

Reviewed by Gavin Barraclough and Sam Weinig

Make the GC mark phase iterative by using an explicit mark stack.
To do this marking any single object is performed in multiple stages

  • The object is appended to the MarkStack, this sets the marked bit for the object using the new markDirect() function, and then returns
  • When the MarkStack is drain()ed the object is popped off the stack and markChildren(MarkStack&) is called on the object to collect all of its children. drain() then repeats until the stack is empty.

Additionally I renamed a number of methods from 'mark' to 'markAggregate'
in order to make it more clear that marking of those object was not
going to result in an actual recursive mark.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/Collector.cpp

    r46703 r47022  
    11/*
    2  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
     2 *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
    33 *  Copyright (C) 2007 Eric Seidel <[email protected]>
    44 *
     
    3131#include "JSString.h"
    3232#include "JSValue.h"
     33#include "MarkStack.h"
    3334#include "Nodes.h"
    3435#include "Tracing.h"
     
    643644#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0)
    644645
    645 void Heap::markConservatively(void* start, void* end)
     646void Heap::markConservatively(MarkStack& markStack, void* start, void* end)
    646647{
    647648    if (start > end) {
     
    684685                if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
    685686                    if (reinterpret_cast<CollectorCell*>(xAsBits)->u.freeCell.zeroIfFree != 0) {
    686                         JSCell* imp = reinterpret_cast<JSCell*>(xAsBits);
    687                         if (!imp->marked())
    688                             imp->mark();
     687                        markStack.append(reinterpret_cast<JSCell*>(xAsBits));
     688                        markStack.drain();
    689689                    }
    690690                    break;
     
    697697}
    698698
    699 void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal()
     699void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal(MarkStack& markStack)
    700700{
    701701    void* dummy;
    702702    void* stackPointer = &dummy;
    703703    void* stackBase = currentThreadStackBase();
    704     markConservatively(stackPointer, stackBase);
    705 }
    706 
    707 void Heap::markCurrentThreadConservatively()
     704    markConservatively(markStack, stackPointer, stackBase);
     705}
     706
     707void Heap::markCurrentThreadConservatively(MarkStack& markStack)
    708708{
    709709    // setjmp forces volatile registers onto the stack
     
    718718#endif
    719719
    720     markCurrentThreadConservativelyInternal();
     720    markCurrentThreadConservativelyInternal(markStack);
    721721}
    722722
     
    850850}
    851851
    852 void Heap::markOtherThreadConservatively(Thread* thread)
     852void Heap::markOtherThreadConservatively(MarkStack& markStack, Thread* thread)
    853853{
    854854    suspendThread(thread->platformThread);
     
    858858
    859859    // mark the thread's registers
    860     markConservatively(static_cast<void*>(&regs), static_cast<void*>(reinterpret_cast<char*>(&regs) + regSize));
     860    markConservatively(markStack, static_cast<void*>(&regs), static_cast<void*>(reinterpret_cast<char*>(&regs) + regSize));
    861861
    862862    void* stackPointer = otherThreadStackPointer(regs);
    863     markConservatively(stackPointer, thread->stackBase);
     863    markConservatively(markStack, stackPointer, thread->stackBase);
    864864
    865865    resumeThread(thread->platformThread);
     
    868868#endif
    869869
    870 void Heap::markStackObjectsConservatively()
    871 {
    872     markCurrentThreadConservatively();
     870void Heap::markStackObjectsConservatively(MarkStack& markStack)
     871{
     872    markCurrentThreadConservatively(markStack);
    873873
    874874#if ENABLE(JSC_MULTIPLE_THREADS)
     
    880880#ifndef NDEBUG
    881881        // Forbid malloc during the mark phase. Marking a thread suspends it, so
    882         // a malloc inside mark() would risk a deadlock with a thread that had been
     882        // a malloc inside markChildren() would risk a deadlock with a thread that had been
    883883        // suspended while holding the malloc lock.
    884884        fastMallocForbid();
     
    888888        for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
    889889            if (!pthread_equal(thread->posixThread, pthread_self()))
    890                 markOtherThreadConservatively(thread);
     890                markOtherThreadConservatively(markStack, thread);
    891891        }
    892892#ifndef NDEBUG
     
    948948}
    949949
    950 void Heap::markProtectedObjects()
     950void Heap::markProtectedObjects(MarkStack& markStack)
    951951{
    952952    if (m_protectedValuesMutex)
     
    956956    for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) {
    957957        JSCell* val = it->first;
    958         if (!val->marked())
    959             val->mark();
     958        if (!val->marked()) {
     959            markStack.append(val);
     960            markStack.drain();
     961        }
    960962    }
    961963
     
    10621064    return numLiveObjects;
    10631065}
    1064    
     1066
    10651067bool Heap::collect()
    10661068{
     
    10811083
    10821084    // MARK: first mark all referenced objects recursively starting out from the set of root objects
    1083 
    1084     markStackObjectsConservatively();
    1085     markProtectedObjects();
     1085    MarkStack& markStack = m_globalData->markStack;
     1086    markStackObjectsConservatively(markStack);
     1087    markProtectedObjects(markStack);
    10861088    if (m_markListSet && m_markListSet->size())
    1087         MarkedArgumentBuffer::markLists(*m_markListSet);
     1089        MarkedArgumentBuffer::markLists(markStack, *m_markListSet);
    10881090    if (m_globalData->exception && !m_globalData->exception.marked())
    1089         m_globalData->exception.mark();
    1090     m_globalData->interpreter->registerFile().markCallFrames(this);
     1091        markStack.append(m_globalData->exception);
     1092    m_globalData->interpreter->registerFile().markCallFrames(markStack, this);
    10911093    m_globalData->smallStrings.mark();
    10921094    if (m_globalData->scopeNodeBeingReparsed)
    1093         m_globalData->scopeNodeBeingReparsed->mark();
     1095        m_globalData->scopeNodeBeingReparsed->markAggregate(markStack);
    10941096    if (m_globalData->firstStringifierToMark)
    1095         JSONObject::markStringifiers(m_globalData->firstStringifierToMark);
    1096 
     1097        JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark);
     1098
     1099    markStack.drain();
     1100    markStack.compact();
    10971101    JAVASCRIPTCORE_GC_MARKED();
    10981102
Note: See TracChangeset for help on using the changeset viewer.