Ignore:
Timestamp:
Oct 17, 2011, 1:43:43 PM (14 years ago)
Author:
[email protected]
Message:

Simplified GC marking logic
https://bugs.webkit.org/show_bug.cgi?id=70258

Reviewed by Filip Pizlo.

No perf. change.

This is a first step toward GC allocating string backing stores, starting
with ropes. It also enables future simplifications and optimizations.

  • Replaced some complex mark stack logic with a simple linear stack of

JSCell pointers.

  • Replaced logic for short-circuiting marking based on JSType and/or

Structure flags with special cases for object, array, and string.

  • Fiddled with inlining for better codegen.
  • heap/Heap.cpp:

(JSC::Heap::Heap): Provide more vptrs to SlotVisitor, for use in marking.

  • heap/HeapRootVisitor.h: Removed unused functions that no longer build.
  • heap/MarkStack.cpp:

(JSC::MarkStackArray::MarkStackArray):
(JSC::MarkStackArray::~MarkStackArray):
(JSC::MarkStackArray::expand):
(JSC::MarkStackArray::shrinkAllocation):
(JSC::MarkStack::reset):
(JSC::visitChildren):
(JSC::SlotVisitor::drain):

  • heap/MarkStack.h:

(JSC::MarkStack::MarkStack):
(JSC::MarkStack::~MarkStack):
(JSC::MarkStackArray::append):
(JSC::MarkStackArray::removeLast):
(JSC::MarkStackArray::isEmpty):
(JSC::MarkStack::append):
(JSC::MarkStack::appendUnbarrieredPointer):
(JSC::MarkStack::internalAppend): Replaced complex mark set logic with
simple linear stack.

  • heap/SlotVisitor.h:

(JSC::SlotVisitor::SlotVisitor): Updated for above changes.

  • runtime/JSArray.cpp:

(JSC::JSArray::visitChildren):

  • runtime/JSArray.h:
  • runtime/JSObject.cpp:

(JSC::JSObject::visitChildren):

  • runtime/JSObject.h: Don't inline visitChildren; it's too big.
  • runtime/Structure.h:

(JSC::MarkStack::internalAppend): Nixed the short-circuit for CompoundType
because it prevented strings from owning GC pointers.

  • runtime/WriteBarrier.h:

(JSC::MarkStack::appendValues): No need to validate; internalAppend will
do that for us.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/heap/MarkStack.cpp

    r97203 r97642  
    3434#include "ScopeChain.h"
    3535#include "Structure.h"
     36#include "WriteBarrier.h"
    3637
    3738namespace JSC {
     39
     40MarkStackArray::MarkStackArray()
     41    : m_top(0)
     42    , m_allocated(pageSize())
     43{
     44    m_data = static_cast<const JSCell**>(MarkStack::allocateStack(m_allocated));
     45    m_capacity = m_allocated / sizeof(JSCell*);
     46}
     47
     48MarkStackArray::~MarkStackArray()
     49{
     50    MarkStack::releaseStack(m_data, m_allocated);
     51}
     52
     53void MarkStackArray::expand()
     54{
     55    size_t oldAllocation = m_allocated;
     56    m_allocated *= 2;
     57    m_capacity = m_allocated / sizeof(JSCell*);
     58    void* newData = MarkStack::allocateStack(m_allocated);
     59    memcpy(newData, m_data, oldAllocation);
     60    MarkStack::releaseStack(m_data, oldAllocation);
     61    m_data = static_cast<const JSCell**>(newData);
     62}
     63
     64void MarkStackArray::shrinkAllocation(size_t size)
     65{
     66    ASSERT(size <= m_allocated);
     67    ASSERT(isPageAligned(size));
     68    if (size == m_allocated)
     69        return;
     70#if OS(WINDOWS)
     71    // We cannot release a part of a region with VirtualFree. To get around this,
     72    // we'll release the entire region and reallocate the size that we want.
     73    MarkStack::releaseStack(m_data, m_allocated);
     74    m_data = static_cast<JSCell*>(MarkStack::allocateStack(size));
     75#else
     76    MarkStack::releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size);
     77#endif
     78    m_allocated = size;
     79    m_capacity = m_allocated / sizeof(JSCell*);
     80}
    3881
    3982void MarkStack::reset()
    4083{
    4184    m_visitCount = 0;
    42     m_values.shrinkAllocation(pageSize());
    43     m_markSets.shrinkAllocation(pageSize());
     85    m_stack.shrinkAllocation(pageSize());
    4486    m_opaqueRoots.clear();
    4587}
     
    5395}
    5496
    55 void SlotVisitor::visitChildren(JSCell* cell)
     97ALWAYS_INLINE static void visitChildren(SlotVisitor& visitor, const JSCell* cell, void* jsFinalObjectVPtr, void* jsArrayVPtr, void* jsStringVPtr)
    5698{
    5799#if ENABLE(SIMPLE_HEAP_PROFILING)
     
    60102
    61103    ASSERT(Heap::isMarked(cell));
    62     if (cell->structure()->typeInfo().type() < CompoundType) {
    63         JSCell::visitChildren(cell, *this);
     104
     105    if (cell->vptr() == jsStringVPtr)
     106        return;
     107
     108    if (cell->vptr() == jsFinalObjectVPtr) {
     109        JSObject::visitChildren(const_cast<JSCell*>(cell), visitor);
    64110        return;
    65111    }
    66112
    67     if (!cell->structure()->typeInfo().overridesVisitChildren()) {
    68         ASSERT(cell->isObject());
    69 #ifdef NDEBUG
    70         asObject(cell)->visitChildrenDirect(*this);
    71 #else
    72         ASSERT(!m_isCheckingForDefaultMarkViolation);
    73         m_isCheckingForDefaultMarkViolation = true;
    74         cell->methodTable()->visitChildren(cell, *this);
    75         ASSERT(m_isCheckingForDefaultMarkViolation);
    76         m_isCheckingForDefaultMarkViolation = false;
    77 #endif
     113    if (cell->vptr() == jsArrayVPtr) {
     114        JSArray::visitChildren(const_cast<JSCell*>(cell), visitor);
    78115        return;
    79116    }
    80     if (cell->vptr() == m_jsArrayVPtr) {
    81         asArray(cell)->visitChildrenDirect(*this);
    82         return;
    83     }
    84     cell->methodTable()->visitChildren(cell, *this);
     117
     118    cell->methodTable()->visitChildren(const_cast<JSCell*>(cell), visitor);
    85119}
    86120
    87121void SlotVisitor::drain()
    88122{
    89 #if !ASSERT_DISABLED
    90     ASSERT(!m_isDraining);
    91     m_isDraining = true;
    92 #endif
    93     while (!m_markSets.isEmpty() || !m_values.isEmpty()) {
    94         while (!m_markSets.isEmpty() && m_values.size() < 50) {
    95             ASSERT(!m_markSets.isEmpty());
    96             MarkSet& current = m_markSets.last();
    97             ASSERT(current.m_values);
    98             JSValue* end = current.m_end;
    99             ASSERT(current.m_values);
    100             ASSERT(current.m_values != end);
    101         findNextUnmarkedNullValue:
    102             ASSERT(current.m_values != end);
    103             JSValue value = *current.m_values;
    104             current.m_values++;
     123    void* jsFinalObjectVPtr = m_jsFinalObjectVPtr;
     124    void* jsArrayVPtr = m_jsArrayVPtr;
     125    void* jsStringVPtr = m_jsStringVPtr;
    105126
    106             JSCell* cell;
    107             if (!value || !value.isCell() || Heap::testAndSetMarked(cell = value.asCell())) {
    108                 if (current.m_values == end) {
    109                     m_markSets.removeLast();
    110                     continue;
    111                 }
    112                 goto findNextUnmarkedNullValue;
    113             }
    114 
    115             if (cell->structure()->typeInfo().type() < CompoundType) {
    116 #if ENABLE(SIMPLE_HEAP_PROFILING)
    117                 m_visitedTypeCounts.count(cell);
    118 #endif
    119                 JSCell::visitChildren(cell, *this);
    120                 if (current.m_values == end) {
    121                     m_markSets.removeLast();
    122                     continue;
    123                 }
    124                 goto findNextUnmarkedNullValue;
    125             }
    126 
    127             if (current.m_values == end)
    128                 m_markSets.removeLast();
    129 
    130             visitChildren(cell);
    131         }
    132         while (!m_values.isEmpty())
    133             visitChildren(m_values.removeLast());
    134     }
    135 #if !ASSERT_DISABLED
    136     m_isDraining = false;
    137 #endif
     127    while (!m_stack.isEmpty())
     128        visitChildren(*this, m_stack.removeLast(), jsFinalObjectVPtr, jsArrayVPtr, jsStringVPtr);
    138129}
    139130
     
    150141
    151142#if ENABLE(GC_VALIDATION)
    152 void MarkStack::validateSet(JSValue* values, size_t count)
     143void MarkStack::validate(JSCell* cell)
    153144{
    154     for (size_t i = 0; i < count; i++) {
    155         if (values[i])
    156             validateValue(values[i]);
    157     }
    158 }
    159 
    160 void MarkStack::validateValue(JSValue value)
    161 {
    162     if (!value)
    163         CRASH();
    164     if (!value.isCell())
    165         return;
    166     JSCell* cell = value.asCell();
    167145    if (!cell)
    168146        CRASH();
     
    177155}
    178156#else
    179 void MarkStack::validateValue(JSValue)
     157void MarkStack::validate(JSCell*)
    180158{
    181 } 
     159}
    182160#endif
    183161
Note: See TracChangeset for help on using the changeset viewer.