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/JSCell.h

    r46598 r47022  
    22 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
    33 *  Copyright (C) 2001 Peter Kelly ([email protected])
    4  *  Copyright (C) 2003, 2004, 2005, 2007, 2008 Apple Inc. All rights reserved.
     4 *  Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
    55 *
    66 *  This library is free software; you can redistribute it and/or
     
    8686        void* operator new(size_t, JSGlobalData*);
    8787        void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; }
    88         virtual void mark();
     88
     89        void markCellDirect();
     90        virtual void markChildren(MarkStack&);
    8991        bool marked() const;
    9092
     
    154156    }
    155157
    156     inline void JSCell::mark()
    157     {
    158         return Heap::markCell(this);
     158    inline void JSCell::markCellDirect()
     159    {
     160        Heap::markCell(this);
     161    }
     162
     163    inline void JSCell::markChildren(MarkStack&)
     164    {
     165        ASSERT(marked());
    159166    }
    160167
     
    225232    }
    226233
    227     inline void JSValue::mark()
    228     {
    229         asCell()->mark(); // callers should check !marked() before calling mark(), so this should only be called with cells
     234    inline void JSValue::markDirect()
     235    {
     236        ASSERT(!marked());
     237        asCell()->markCellDirect();
     238    }
     239
     240    inline void JSValue::markChildren(MarkStack& markStack)
     241    {
     242        ASSERT(marked());
     243        asCell()->markChildren(markStack);
    230244    }
    231245
     
    340354        return JSValue();
    341355    }
     356   
     357    inline bool JSValue::hasChildren() const
     358    {
     359        return asCell()->structure()->typeInfo().type() >= CompoundType;
     360    }
     361   
    342362
    343363    inline JSObject* JSValue::toObject(ExecState* exec) const
     
    351371    }
    352372
     373    ALWAYS_INLINE void MarkStack::append(JSCell* cell)
     374    {
     375        ASSERT(cell);
     376        if (cell->marked())
     377            return;
     378        cell->markCellDirect();
     379        if (cell->structure()->typeInfo().type() >= CompoundType)
     380            m_values.append(cell);
     381    }
     382
     383    inline void MarkStack::drain() {
     384        while (!m_markSets.isEmpty() || !m_values.isEmpty()) {
     385            while ((!m_markSets.isEmpty()) && m_values.size() < 50) {
     386                const MarkSet& current = m_markSets.removeLast();
     387                JSValue* ptr = current.m_values;
     388                JSValue* end = current.m_end;
     389                if (current.m_properties == NoNullValues) {
     390                    while (ptr != end)
     391                        append(*ptr++);
     392                } else {
     393                    while (ptr != end) {
     394                        if (JSValue value = *ptr++)
     395                            append(value);
     396                    }
     397                }
     398            }
     399            while (!m_values.isEmpty()) {
     400                JSCell* current = m_values.removeLast();
     401                ASSERT(current->marked());
     402                current->markChildren(*this);
     403            }
     404        }
     405    }
    353406} // namespace JSC
    354407
Note: See TracChangeset for help on using the changeset viewer.