/* * Copyright (C) 2009, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "MarkStack.h" #include "ConservativeRoots.h" #include "Heap.h" #include "JSArray.h" #include "JSCell.h" #include "JSObject.h" #include "ScopeChain.h" #include "Structure.h" namespace JSC { size_t MarkStack::s_pageSize = 0; void MarkStack::reset() { ASSERT(s_pageSize); m_values.shrinkAllocation(s_pageSize); m_markSets.shrinkAllocation(s_pageSize); m_opaqueRoots.clear(); } void MarkStack::append(ConservativeRoots& conservativeRoots) { JSCell** roots = conservativeRoots.roots(); size_t size = conservativeRoots.size(); for (size_t i = 0; i < size; ++i) internalAppend(roots[i]); } inline void MarkStack::markChildren(JSCell* cell) { ASSERT(Heap::isMarked(cell)); if (cell->structure()->typeInfo().type() < CompoundType) { cell->JSCell::markChildren(*this); return; } if (!cell->structure()->typeInfo().overridesMarkChildren()) { ASSERT(cell->isObject()); #ifdef NDEBUG asObject(cell)->markChildrenDirect(*this); #else ASSERT(!m_isCheckingForDefaultMarkViolation); m_isCheckingForDefaultMarkViolation = true; cell->markChildren(*this); ASSERT(m_isCheckingForDefaultMarkViolation); m_isCheckingForDefaultMarkViolation = false; #endif return; } if (cell->vptr() == m_jsArrayVPtr) { asArray(cell)->markChildrenDirect(*this); return; } cell->markChildren(*this); } void MarkStack::drain() { #if !ASSERT_DISABLED ASSERT(!m_isDraining); m_isDraining = true; #endif while (!m_markSets.isEmpty() || !m_values.isEmpty()) { while (!m_markSets.isEmpty() && m_values.size() < 50) { ASSERT(!m_markSets.isEmpty()); MarkSet& current = m_markSets.last(); ASSERT(current.m_values); JSValue* end = current.m_end; ASSERT(current.m_values); ASSERT(current.m_values != end); findNextUnmarkedNullValue: ASSERT(current.m_values != end); JSValue value = *current.m_values; current.m_values++; JSCell* cell; if (!value || !value.isCell() || Heap::testAndSetMarked(cell = value.asCell())) { if (current.m_values == end) { m_markSets.removeLast(); continue; } goto findNextUnmarkedNullValue; } if (cell->structure()->typeInfo().type() < CompoundType) { cell->JSCell::markChildren(*this); if (current.m_values == end) { m_markSets.removeLast(); continue; } goto findNextUnmarkedNullValue; } if (current.m_values == end) m_markSets.removeLast(); markChildren(cell); } while (!m_values.isEmpty()) markChildren(m_values.removeLast()); } #if !ASSERT_DISABLED m_isDraining = false; #endif } } // namespace JSC