blob: 1504637a080a83fc376002c1d0e5ce0e1754887e [file] [log] [blame]
/*
* Copyright (C) 2014, 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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 "GCLogging.h"
#include "ClassInfo.h"
#include "Heap.h"
#include "HeapIterationScope.h"
#include "JSCell.h"
#include "JSCellInlines.h"
#include <wtf/PrintStream.h>
namespace JSC {
const char* GCLogging::levelAsString(Level level)
{
switch (level) {
case None:
return "None";
case Basic:
return "Basic";
case Verbose:
return "Verbose";
default:
RELEASE_ASSERT_NOT_REACHED();
return "";
}
}
class LoggingFunctor {
public:
LoggingFunctor(SlotVisitor& slotVisitor)
: m_slotVisitor(slotVisitor)
{
m_savedMarkStack.resize(m_slotVisitor.markStack().size());
m_slotVisitor.markStack().fillVector(m_savedMarkStack);
}
~LoggingFunctor()
{
reviveCells();
}
IterationStatus operator()(JSCell* cell)
{
m_liveCells.append(cell);
MarkedBlock::blockFor(cell)->clearMarked(cell);
return IterationStatus::Continue;
}
void log()
{
m_slotVisitor.clearMarkStack();
for (JSCell* cell : m_liveCells) {
cell->methodTable()->visitChildren(cell, m_slotVisitor);
dataLog("\n", *cell, ":\n", m_slotVisitor);
for (const JSCell* neighbor : m_slotVisitor.markStack())
MarkedBlock::blockFor(neighbor)->clearMarked(neighbor);
m_slotVisitor.clearMarkStack();
}
m_slotVisitor.reset();
}
void reviveCells()
{
for (JSCell* cell : m_liveCells)
MarkedBlock::blockFor(cell)->setMarked(cell);
for (const JSCell* cell : m_savedMarkStack) {
m_slotVisitor.markStack().append(cell);
cell->setCellState(CellState::OldGrey);
}
}
typedef void ReturnType;
void returnValue() { };
private:
Vector<const JSCell*> m_savedMarkStack;
Vector<JSCell*> m_liveCells;
SlotVisitor& m_slotVisitor;
};
void GCLogging::dumpObjectGraph(Heap* heap)
{
LoggingFunctor loggingFunctor(heap->m_slotVisitor);
HeapIterationScope iterationScope(*heap);
heap->objectSpace().forEachLiveCell(iterationScope, loggingFunctor);
loggingFunctor.log();
}
} // namespace JSC
namespace WTF {
void printInternal(PrintStream& out, JSC::GCLogging::Level level)
{
switch (level) {
case JSC::GCLogging::Level::None:
out.print("None");
return;
case JSC::GCLogging::Level::Basic:
out.print("Basic");
return;
case JSC::GCLogging::Level::Verbose:
out.print("Verbose");
return;
default:
out.print("Level=", level - JSC::GCLogging::Level::None);
return;
}
}
} // namespace WTF