blob: fcb30e5b802ee2d623d6d53793954c1a4435c9a1 [file] [log] [blame]
/*
* Copyright (C) 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 "DFGGraph.h"
#include "CodeBlock.h"
#if ENABLE(DFG_JIT)
namespace JSC { namespace DFG {
#ifndef NDEBUG
// Creates an array of stringized names.
static const char* dfgOpNames[] = {
#define STRINGIZE_DFG_OP_ENUM(opcode, flags) #opcode ,
FOR_EACH_DFG_OP(STRINGIZE_DFG_OP_ENUM)
#undef STRINGIZE_DFG_OP_ENUM
};
const char *Graph::opName(NodeType op)
{
return dfgOpNames[op & NodeIdMask];
}
void Graph::dump(NodeIndex nodeIndex, CodeBlock* codeBlock)
{
Node& node = at(nodeIndex);
NodeType op = node.op;
unsigned refCount = node.refCount();
bool skipped = !refCount;
bool mustGenerate = node.mustGenerate();
if (mustGenerate) {
ASSERT(refCount);
--refCount;
}
// Example/explanation of dataflow dump output
//
// 14: <!2:7> GetByVal(@3, @13)
// ^1 ^2 ^3 ^4 ^5
//
// (1) The nodeIndex of this operation.
// (2) The reference count. The number printed is the 'real' count,
// not including the 'mustGenerate' ref. If the node is
// 'mustGenerate' then the count it prefixed with '!'.
// (3) The virtual register slot assigned to this node.
// (4) The name of the operation.
// (5) The arguments to the operation. The may be of the form:
// @# - a NodeIndex referencing a prior node in the graph.
// arg# - an argument number.
// $# - the index in the CodeBlock of a constant { for numeric constants the value is displayed | for integers, in both decimal and hex }.
// id# - the index in the CodeBlock of an identifier { if codeBlock is passed to dump(), the string representation is displayed }.
// var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations.
printf("% 4d:%s<%c%u:", (int)nodeIndex, skipped ? " skipped " : " ", mustGenerate ? '!' : ' ', refCount);
if (node.hasResult() && !skipped)
printf("%u", node.virtualRegister());
else
printf("-");
printf(">\t%s(", opName(op));
bool hasPrinted = false;
if (op & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++) {
if (hasPrinted)
printf(", ");
else
hasPrinted = true;
printf("@%u", m_varArgChildren[childIdx]);
}
} else {
if (node.child1() != NoNode)
printf("@%u", node.child1());
if (node.child2() != NoNode)
printf(", @%u", node.child2());
if (node.child3() != NoNode)
printf(", @%u", node.child3());
hasPrinted = node.child1() != NoNode;
}
if (node.hasVarNumber()) {
printf("%svar%u", hasPrinted ? ", " : "", node.varNumber());
hasPrinted = true;
}
if (node.hasIdentifier()) {
if (codeBlock)
printf("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), codeBlock->identifier(node.identifierNumber()).ustring().utf8().data());
else
printf("%sid%u", hasPrinted ? ", " : "", node.identifierNumber());
hasPrinted = true;
}
if (node.hasLocal()) {
int local = node.local();
if (operandIsArgument(local))
printf("%sarg%u", hasPrinted ? ", " : "", local - codeBlock->thisRegister());
else
printf("%sr%u", hasPrinted ? ", " : "", local);
hasPrinted = true;
}
if (op == JSConstant) {
printf("%s$%u", hasPrinted ? ", " : "", node.constantNumber());
if (codeBlock) {
JSValue value = node.valueOfJSConstant(codeBlock);
printf(" = %s", value.description());
}
hasPrinted = true;
}
if (node.isBranch() || node.isJump()) {
printf("%sT:#%u", hasPrinted ? ", " : "", blockIndexForBytecodeOffset(node.takenBytecodeOffset()));
hasPrinted = true;
}
if (node.isBranch()) {
printf("%sF:#%u", hasPrinted ? ", " : "", blockIndexForBytecodeOffset(node.notTakenBytecodeOffset()));
hasPrinted = true;
}
(void)hasPrinted;
printf(")");
if (node.hasLocal())
printf(" predicting %s", predictionToString(getPrediction(node.local())));
if (node.hasVarNumber())
printf(" predicting %s", predictionToString(getGlobalVarPrediction(node.varNumber())));
if (node.hasPrediction())
printf(" predicting %s", predictionToString(node.getPrediction()));
printf("\n");
}
void Graph::dump(CodeBlock* codeBlock)
{
for (size_t b = 0; b < m_blocks.size(); ++b) {
printf("Block #%u:\n", (int)b);
for (size_t i = m_blocks[b]->begin; i < m_blocks[b]->end; ++i)
dump(i, codeBlock);
}
printf("Phi Nodes:\n");
for (size_t i = m_blocks.last()->end; i < size(); ++i)
dump(i, codeBlock);
}
#endif
// FIXME: Convert this method to be iterative, not recursive.
void Graph::refChildren(NodeIndex op)
{
Node& node = at(op);
if (node.op & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
ref(m_varArgChildren[childIdx]);
} else {
if (node.child1() == NoNode) {
ASSERT(node.child2() == NoNode && node.child3() == NoNode);
return;
}
ref(node.child1());
if (node.child2() == NoNode) {
ASSERT(node.child3() == NoNode);
return;
}
ref(node.child2());
if (node.child3() == NoNode)
return;
ref(node.child3());
}
}
void Graph::predictArgumentTypes(ExecState* exec, CodeBlock* codeBlock)
{
if (exec) {
size_t numberOfArguments = std::min(exec->argumentCountIncludingThis(), m_predictions.numberOfArguments());
for (size_t arg = 1; arg < numberOfArguments; ++arg) {
JSValue argumentValue = exec->argument(arg - 1);
if (argumentValue.isInt32())
m_predictions.predictArgument(arg, PredictInt32, WeakPrediction);
else if (argumentValue.isDouble())
m_predictions.predictArgument(arg, PredictDouble, WeakPrediction);
}
}
#if ENABLE(DYNAMIC_OPTIMIZATION)
ASSERT(codeBlock);
ASSERT(codeBlock->alternative);
JSGlobalData& globalData = exec->globalData();
CodeBlock* profiledCodeBlock = codeBlock->alternative();
ASSERT(codeBlock->m_numParameters >= 1);
for (size_t arg = 1; arg < static_cast<size_t>(codeBlock->m_numParameters); ++arg) {
ValueProfile* profile = profiledCodeBlock->valueProfileForArgument(arg);
if (!profile)
continue;
#if ENABLE(DFG_DEBUG_VERBOSE)
printf("Argument profile [%lu]: ", arg);
profile->dump(stdout);
printf("\n");
#endif
m_predictions.predictArgument(arg, makePrediction(globalData, *profile) & ~PredictionTagMask, StrongPrediction);
#if ENABLE(DFG_DEBUG_VERBOSE)
printf(" Prediction: %s\n", predictionToString(m_predictions.getArgumentPrediction(arg)));
#endif
}
#else
UNUSED_PARAM(codeBlock);
#endif
}
} } // namespace JSC::DFG
#endif