mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 12:37:37 +00:00
578 lines
17 KiB
C++
578 lines
17 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
#include "ControlGraph.h"
|
|
#include "DebugUtils.h"
|
|
|
|
|
|
const ControlKindProperties controlKindProperties[nControlKinds] =
|
|
{// Incoming--- Outgoing----------
|
|
// Norml? Exc? Norml? Exc? One?
|
|
{false, false, false, false, false}, // ckNone
|
|
{false, false, true, false, true}, // ckBegin
|
|
{false, true, false, false, false}, // ckEnd
|
|
{true, false, true, false, true}, // ckBlock
|
|
{true, false, true, false, false}, // ckIf
|
|
{true, false, true, false, false}, // ckSwitch
|
|
{true, false, true, true, true}, // ckExc
|
|
{true, false, false, true, false}, // ckThrow
|
|
{true, false, true, true, true}, // ckAExc
|
|
{false, true, true, false, true}, // ckCatch
|
|
{true, false, false, false, false} // ckReturn
|
|
};
|
|
|
|
|
|
#ifdef DEBUG_LOG
|
|
const char controlKindNames[][8] =
|
|
{
|
|
"????", // ckNone
|
|
"Begin", // ckBegin
|
|
"End", // ckEnd
|
|
"Block", // ckBlock
|
|
"If", // ckIf
|
|
"Switch", // ckSwitch
|
|
"Exc", // ckExc
|
|
"Throw", // ckThrow
|
|
"AExc", // ckAExc
|
|
"Catch", // ckCatch
|
|
"Return" // ckReturn
|
|
};
|
|
|
|
|
|
//
|
|
// Print the name of the ControlKind onto the output stream f.
|
|
// Return the number of characters printed.
|
|
//
|
|
int print(LogModuleObject &f, ControlKind ck)
|
|
{
|
|
return UT_OBJECTLOG(f, PR_LOG_ALWAYS, ((uint)ck > ckReturn ? "????" : controlKindNames[ck]));
|
|
}
|
|
#endif
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ControlNode::BeginExtra
|
|
|
|
//
|
|
// Initialize a new BeginExtra record with nArguments incoming arguments whose
|
|
// kinds are given by argumentKinds. If the method isn't static, the this
|
|
// parameter must be listed as an incoming argument in the argumentKinds array
|
|
// as well and hasSelfArgument must be set to true; otherwise hasSelfArgument
|
|
// should be false.
|
|
// Allocate additional storage for the arguments array from the given pool.
|
|
//
|
|
ControlNode::BeginExtra::BeginExtra(ControlNode &controlNode, Pool &pool,
|
|
uint nArguments,
|
|
const ValueKind *argumentKinds,
|
|
bool hasSelfArgument, Uint32 bci)
|
|
: nArguments(nArguments),
|
|
arguments(nArguments ? new(pool) PrimArg[nArguments] : 0)
|
|
{
|
|
initialMemory.initOutgoingEdge(vkMemory, true);
|
|
controlNode.appendPrimitive(initialMemory);
|
|
PrimArg *a = arguments;
|
|
bool isThis = hasSelfArgument;
|
|
for (uint i = 0; i != nArguments; i++) {
|
|
// Set the bytecode index. This can't be done in the constructor
|
|
// because initializers can't be specified for an array of objects
|
|
// allocated through the new operator
|
|
a->setBytecodeIndex(bci);
|
|
a->initOutgoingEdge(*argumentKinds++, isThis);
|
|
isThis = false;
|
|
controlNode.appendPrimitive(*a);
|
|
a++;
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ControlNode::ReturnExtra
|
|
|
|
//
|
|
// Initialize a new ReturnExtra record with nResults results whose kinds are
|
|
// given in the resultKinds array.
|
|
// Allocate additional storage for the results array from the given pool.
|
|
//
|
|
ControlNode::ReturnExtra::ReturnExtra(ControlNode &controlNode, Pool &pool,
|
|
uint nResults,
|
|
const ValueKind *resultKinds, Uint32 bci)
|
|
: nResults(nResults), results((PrimResult * const)pool.allocate(nResults * sizeof(PrimResult)))
|
|
{
|
|
uint i;
|
|
PrimResult *r = results;
|
|
for (i = 0; i != nResults; i++) {
|
|
new (r) PrimResult(bci);
|
|
r->setResultKind(*resultKinds++);
|
|
controlNode.appendPrimitive(*r++);
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ControlNode
|
|
|
|
Uint32 ControlNode::nextGeneration = 1;
|
|
|
|
|
|
#ifdef DEBUG
|
|
//
|
|
// Return true if each phi node in this ControlNode has the same number of
|
|
// inputs as this ControlNode has predecessors.
|
|
// If phisDisengaged is nonzero, always return true.
|
|
//
|
|
bool ControlNode::phisConsistent() const
|
|
{
|
|
if (phisDisengaged)
|
|
return true;
|
|
Uint32 nPredecessors = predecessors.length();
|
|
for (DoublyLinkedList<PhiNode>::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i))
|
|
if (phiNodes.get(i).nInputs() != nPredecessors)
|
|
return false;
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Return the number of successor edges that are not exception or return edges.
|
|
// Multiple edges to the same node are counted multiple times.
|
|
//
|
|
Uint32 ControlNode::nNormalSuccessors() const
|
|
{
|
|
switch (controlKind) {
|
|
case ckEnd:
|
|
case ckThrow:
|
|
case ckReturn:
|
|
return 0;
|
|
case ckBegin:
|
|
case ckBlock:
|
|
case ckExc:
|
|
case ckAExc:
|
|
case ckCatch:
|
|
return 1;
|
|
case ckIf:
|
|
return 2;
|
|
case ckSwitch:
|
|
return nSuccessors();
|
|
case ckNone:;
|
|
}
|
|
trespass("Bad control node");
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate exactly one successor for this ControlNode.
|
|
//
|
|
void ControlNode::setOneSuccessor()
|
|
{
|
|
ControlEdge *successor = new(getPrimitivePool()) ControlEdge;
|
|
successor->setSource(*this);
|
|
setSuccessors(successor, successor + 1);
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate n successors for this ControlNode.
|
|
//
|
|
void ControlNode::setNSuccessors(Uint32 n)
|
|
{
|
|
ControlEdge *successors = new(getPrimitivePool()) ControlEdge[n];
|
|
ControlEdge *successors2 = successors;
|
|
while (n--)
|
|
successors2++->setSource(*this);
|
|
setSuccessors(successors, successors2);
|
|
}
|
|
|
|
|
|
//
|
|
// Use n preallocated successors for this ControlNode.
|
|
// Make the successors's sources point to this ControlNode.
|
|
//
|
|
inline void ControlNode::setNSuccessors(Uint32 n, ControlEdge *successors)
|
|
{
|
|
setSuccessors(successors, successors + n);
|
|
while (n--)
|
|
successors++->setSource(*this);
|
|
}
|
|
|
|
|
|
//
|
|
// Unset the control node's kind so that the node can get a new kind.
|
|
// The primitives and phi nodes remain attached to this control node, but
|
|
// the control kind-specific data disappears.
|
|
// The successor ControlEdges' targets must have been initialized prior
|
|
// to calling this method; this method clears them.
|
|
//
|
|
void ControlNode::clearControlKind()
|
|
{
|
|
#if defined(DEBUG) || defined(DEBUG_LOG)
|
|
controlKind = ckNone;
|
|
#endif
|
|
for (ControlEdge *e = successorsBegin; e != successorsEnd; e++)
|
|
e->clearTarget();
|
|
#ifdef DEBUG
|
|
successorsBegin = 0;
|
|
successorsEnd = 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
//
|
|
// Unset the control node's kind so that the node can get a new kind.
|
|
// The primitives and phi nodes remain attached to this control node, but
|
|
// the control kind-specific data disappears.
|
|
// The successor ControlEdges' targets must have been initialized prior
|
|
// to calling this method; this method clears them.
|
|
//
|
|
// Return a location suitable for relinking another edge to the control
|
|
// node's normal outgoing edge's target in place of the existing normal
|
|
// outgoing edge without disturbing the order of that target's
|
|
// predecessors (changing that order would disrupt the target's phi nodes).
|
|
// This control node must have exactly one normal outgoing edge.
|
|
//
|
|
DoublyLinkedList<ControlEdge>::iterator ControlNode::clearControlKindOne()
|
|
{
|
|
assert(hasOneNormalOutgoingEdge(getControlKind()) && successorsBegin);
|
|
#if defined(DEBUG) || defined(DEBUG_LOG)
|
|
controlKind = ckNone;
|
|
#endif
|
|
ControlEdge *e = successorsBegin;
|
|
DoublyLinkedList<ControlEdge>::iterator where = e->clearTarget();
|
|
while (++e != successorsEnd)
|
|
e->clearTarget();
|
|
#ifdef DEBUG
|
|
successorsBegin = 0;
|
|
successorsEnd = 0;
|
|
#endif
|
|
return where;
|
|
}
|
|
|
|
|
|
//
|
|
// Designate the ControlNode to be a Begin node with nArguments incoming arguments
|
|
// whose kinds are given by argumentKinds. If the method isn't static, the this
|
|
// parameter must be listed as an incoming argument in the argumentKinds array
|
|
// as well and hasSelfArgument must be set to true; otherwise hasSelfArgument
|
|
// should be false.
|
|
// Afterwards the caller must initialize the successor ControlEdge's target.
|
|
//
|
|
void ControlNode::setControlBegin(uint nArguments,
|
|
const ValueKind *argumentKinds,
|
|
bool hasSelfArgument, Uint32 bci)
|
|
{
|
|
assert(controlKind == ckNone);
|
|
|
|
setOneSuccessor();
|
|
Pool &pool = getPrimitivePool();
|
|
beginExtra = new(pool) BeginExtra(*this, pool, nArguments, argumentKinds,
|
|
hasSelfArgument, bci);
|
|
controlKind = ckBegin;
|
|
}
|
|
|
|
|
|
//
|
|
// Designate the ControlNode to be an End node.
|
|
// The caller must subsequently initialize the finalMemory's incoming edge.
|
|
//
|
|
void ControlNode::setControlEnd(Uint32 bci)
|
|
{
|
|
assert(controlKind == ckNone);
|
|
|
|
ControlEdge e;
|
|
setSuccessors(&e, &e); // No successors.
|
|
endExtra = new(getPrimitivePool()) EndExtra(bci);
|
|
appendPrimitive(endExtra->finalMemory);
|
|
controlKind = ckEnd;
|
|
}
|
|
|
|
|
|
//
|
|
// Designate the ControlNode to be a Block node.
|
|
// Afterwards the caller must initialize the successor ControlEdge's target.
|
|
//
|
|
void ControlNode::setControlBlock()
|
|
{
|
|
assert(controlKind == ckNone);
|
|
|
|
setOneSuccessor();
|
|
controlKind = ckBlock;
|
|
}
|
|
|
|
//
|
|
// Designate the ControlNode to be an If node that tests the given
|
|
// conditional. condition must be a DataNode that generates a condition
|
|
// value. Afterwards the caller must initialize the two successor
|
|
// ControlEdges' targets.
|
|
//
|
|
void
|
|
ControlNode::setControlIf(Condition2 conditional, DataNode &condition,
|
|
Uint32 bci)
|
|
{
|
|
assert(controlKind == ckNone && condition.hasKind(vkCond));
|
|
|
|
setNSuccessors(2);
|
|
PrimControl *pc = new(getPrimitivePool())
|
|
PrimControl(condition2ToIfCond(conditional), bci);
|
|
pc->getInput().setVariable(condition);
|
|
appendPrimitive(*pc);
|
|
controlPrimExtra = pc;
|
|
controlKind = ckIf;
|
|
}
|
|
|
|
|
|
//
|
|
// Designate the ControlNode to be a Switch node with nCases cases. selector
|
|
// must be a DataNode that generates an int value. Afterwards the caller
|
|
// must initialize all the successor ControlEdges' targets.
|
|
//
|
|
void
|
|
ControlNode::setControlSwitch(DataNode &selector, Uint32 nCases, Uint32 bci)
|
|
{
|
|
assert(controlKind == ckNone && selector.hasKind(vkInt) && nCases > 0);
|
|
|
|
setNSuccessors(nCases);
|
|
PrimControl *pc = new(getPrimitivePool()) PrimControl(poSwitch, bci);
|
|
pc->getInput().setVariable(selector);
|
|
appendPrimitive(*pc);
|
|
controlPrimExtra = pc;
|
|
controlKind = ckSwitch;
|
|
}
|
|
|
|
|
|
//
|
|
// Designate the ControlNode to be an Exc, Throw, or AExc node, depending on
|
|
// the given ControlKind. The node will have nHandlers exception handlers
|
|
// with that many filter classes listed in the handlerFilters array. The
|
|
// exception classes are considered in order when dispatching an exception,
|
|
// so their order is significant. If the ControlNode will be an Exc or Throw
|
|
// node, tryPrimitive must be a primitive located inside this node that can
|
|
// throw an exception; if the ControlNode will be an AExc node, tryPrimitive
|
|
// must be nil. successors must be a preallocated array of nHandlers or
|
|
// nHandlers+1 successor edges, including the edge referring to the normal
|
|
// successor for Exc and AExc nodes.
|
|
//
|
|
// The caller must initialize all the successor ControlEdges' targets either
|
|
// before or after calling this method.
|
|
//
|
|
void
|
|
ControlNode::setControlException(ControlKind ck, Uint32 nHandlers,
|
|
const Class **handlerFilters,
|
|
Primitive *tryPrimitive,
|
|
ControlEdge *successors)
|
|
{
|
|
assert(controlKind == ckNone &&
|
|
hasExceptionOutgoingEdges(ck) && nHandlers > 0 &&
|
|
(tryPrimitive == 0) == (ck == ckAExc));
|
|
|
|
bool hasNormalExit = ck != ckThrow;
|
|
setNSuccessors(hasNormalExit + nHandlers, successors);
|
|
|
|
ExceptionExtra *ee;
|
|
if (tryPrimitive)
|
|
ee = new(getPrimitivePool()) TryExtra(tryPrimitive);
|
|
else
|
|
ee = new(getPrimitivePool()) ExceptionExtra;
|
|
ee->nHandlers = nHandlers;
|
|
ee->handlerFilters = handlerFilters;
|
|
exceptionExtra = ee;
|
|
controlKind = ck;
|
|
}
|
|
|
|
|
|
//
|
|
// Designate the ControlNode to be a Catch node. Return the node's PrimCatch
|
|
// primitive. Afterwards the caller must initialize the successor
|
|
// ControlEdge's target.
|
|
//
|
|
PrimCatch &
|
|
ControlNode::setControlCatch(Uint32 bci)
|
|
{
|
|
assert(controlKind == ckNone);
|
|
|
|
setOneSuccessor();
|
|
catchExtra = new(getPrimitivePool()) CatchExtra(bci);
|
|
PrimCatch &cause = catchExtra->cause;
|
|
prependPrimitive(cause);
|
|
controlKind = ckCatch;
|
|
return cause;
|
|
}
|
|
|
|
|
|
//
|
|
// Designate the ControlNode to be a Return node with nResults results whose
|
|
// kinds are given in the resultKinds array. Afterwards the caller must
|
|
// initialize the successor ControlEdge's target to point to the End node and
|
|
// call getReturnExtra()[...].getInput() = ... for each result
|
|
//
|
|
void ControlNode::setControlReturn(uint nResults,
|
|
const ValueKind *resultKinds, Uint32 bci)
|
|
{
|
|
assert(controlKind == ckNone);
|
|
|
|
setOneSuccessor();
|
|
Pool &pool = getPrimitivePool();
|
|
returnExtra = new(pool) ReturnExtra(*this, pool, nResults, resultKinds,
|
|
bci);
|
|
controlKind = ckReturn;
|
|
controlGraph.setReturnNode(*this);
|
|
}
|
|
|
|
|
|
//
|
|
// Move the predecessors from the given list to this ControlNode.
|
|
// This ControlNode must have no current predecessors.
|
|
// On return, the src list will be made empty because the ControlEdges can
|
|
// be linked into only one DoublyLinkedList at a time.
|
|
//
|
|
void ControlNode::movePredecessors(DoublyLinkedList<ControlEdge> &src)
|
|
{
|
|
assert(phisDisengaged || phiNodes.empty());
|
|
predecessors.move(src);
|
|
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin();
|
|
!predecessors.done(i);
|
|
i = predecessors.advance(i))
|
|
predecessors.get(i).setTarget(*this);
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
//
|
|
// Temporary routine to print out the list of instructions which are valid after scheduling.
|
|
//
|
|
void ControlNode::printScheduledInstructions(LogModuleObject &f)
|
|
{
|
|
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i))
|
|
{
|
|
instructions.get(i).getPrimitive()->printPretty(f, 2);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\t\t"));
|
|
instructions.get(i).printDebug(f);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n"));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG_LOG
|
|
//
|
|
// Print a reference to this ControlNode for debugging purposes.
|
|
// Return the number of characters printed.
|
|
//
|
|
int ControlNode::printRef(LogModuleObject &f) const
|
|
{
|
|
if (controlGraph.dfsListIsValid() && dfsNum >= 0)
|
|
return UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("N%d", dfsNum));
|
|
else
|
|
return UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("N%p", this));
|
|
}
|
|
|
|
|
|
//
|
|
// Print a ControlNode for debugging purposes.
|
|
// f should be at the beginning of a line.
|
|
//
|
|
void ControlNode::printPretty(LogModuleObject &f, int margin) const
|
|
{
|
|
printMargin(f, margin);
|
|
if (controlKind != ckNone) {
|
|
print(f, controlKind);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" "));
|
|
}
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Node "));
|
|
printRef(f);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" (%p):\n", this));
|
|
|
|
printMargin(f, margin);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Predecessors: "));
|
|
bool printSeparator = false;
|
|
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i)) {
|
|
ControlEdge &e = predecessors.get(i);
|
|
if (printSeparator)
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (", "));
|
|
printSeparator = true;
|
|
assert(&e.getTarget() == this);
|
|
e.getSource().printRef(f);
|
|
}
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n"));
|
|
|
|
if (!phiNodes.empty()) {
|
|
printMargin(f, margin);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Phi nodes:\n"));
|
|
for (DoublyLinkedList<PhiNode>::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
|
|
PhiNode &n = phiNodes.get(i);
|
|
assert(n.getContainer() == this);
|
|
n.printPretty(f, margin + 4);
|
|
}
|
|
}
|
|
|
|
if (!primitives.empty()) {
|
|
printMargin(f, margin);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Primitives:\n"));
|
|
for (DoublyLinkedList<Primitive>::iterator i = primitives.begin(); !primitives.done(i); i = primitives.advance(i)) {
|
|
Primitive &n = primitives.get(i);
|
|
assert(n.getContainer() == this);
|
|
n.printPretty(f, margin + 4);
|
|
}
|
|
}
|
|
|
|
if (successorsBegin && successorsEnd) {
|
|
ControlEdge *e = successorsBegin;
|
|
ControlEdge *eEnd = e + nNormalSuccessors() + hasControlKind(ckReturn);
|
|
if (e != eEnd) {
|
|
printMargin(f, margin);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Successors: "));
|
|
bool printSeparator = false;
|
|
while (e != eEnd) {
|
|
if (printSeparator)
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (", "));
|
|
printSeparator = true;
|
|
assert(&e->getSource() == this);
|
|
e->getTarget().printRef(f);
|
|
e++;
|
|
}
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n"));
|
|
}
|
|
if (e != successorsEnd) {
|
|
ExceptionExtra *ee = &getExceptionExtra();
|
|
assert((Uint32)(successorsEnd - e) == ee->nHandlers);
|
|
printMargin(f, margin);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Exception handlers: "));
|
|
bool printSeparator = false;
|
|
const Class **exceptionClass = ee->handlerFilters;
|
|
while (e != successorsEnd) {
|
|
if (printSeparator)
|
|
printMargin(f, margin + 20);
|
|
printSeparator = true;
|
|
assert(&e->getSource() == this);
|
|
(*exceptionClass++)->printRef(f);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" -> "));
|
|
e->getTarget().printRef(f);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n"));
|
|
e++;
|
|
}
|
|
}
|
|
}
|
|
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n"));
|
|
}
|
|
#endif
|