mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
604 lines
27 KiB
C++
604 lines
27 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 "GraphUtils.h"
|
|
|
|
#ifdef DEBUG
|
|
|
|
UT_DEFINE_LOG_MODULE(GraphVerifier);
|
|
|
|
//#define CARRY_ON_VERIFYING
|
|
|
|
#ifdef CARRY_ON_VERIFYING
|
|
#define VERIFY_ASSERT(cond) ( (!(cond)) ? UT_LOG(GraphVerifier, PR_LOG_ALWAYS, ("Verify failure - '%s' @ %s %d \n", #cond, __FILE__, __LINE__)) : 0 )
|
|
#else
|
|
#define VERIFY_ASSERT(cond) assert((cond))
|
|
#endif
|
|
|
|
|
|
|
|
void ControlGraph::validate()
|
|
{
|
|
UT_LOG(GraphVerifier, PR_LOG_ALWAYS, ("\n*** Verifying control graph 0x%p\n", this));
|
|
|
|
|
|
VERIFY_ASSERT(!controlNodes.empty());
|
|
VERIFY_ASSERT(nNodes >= 2);
|
|
|
|
dfsSearch(); // we use the dfs numbers to enforce the backward edge constraint, and as indices
|
|
// into handy-dandy tables of marks and reachingSets, thus...
|
|
|
|
Uint32 *connectedSearchMark = new Uint32[nNodes];
|
|
FastBitSet **reachingSet = new FastBitSet *[nNodes];
|
|
|
|
|
|
// prove that there's only one begin and end node, and optionally one return node,
|
|
// and that they're on the graph
|
|
bool foundBeginNode = false, foundEndNode = false, foundReturnNode = false;
|
|
DoublyLinkedList<ControlNode>::iterator cni;
|
|
Uint32 controlNodeCount = 0;
|
|
for (cni = controlNodes.begin(); !controlNodes.done(cni); cni = controlNodes.advance(cni))
|
|
{
|
|
ControlNode &cn = controlNodes.get(cni);
|
|
controlNodeCount++;
|
|
connectedSearchMark[cn.dfsNum] = ControlNode::unmarked; // prepare for the connected search below
|
|
if (cn.hasControlKind(ckBegin)) {
|
|
VERIFY_ASSERT(!foundBeginNode); /* CONSTRAINT 'BEGIN1' */
|
|
VERIFY_ASSERT(&cn == &beginNode);
|
|
foundBeginNode = true;
|
|
}
|
|
if (cn.hasControlKind(ckEnd)) {
|
|
VERIFY_ASSERT(!foundEndNode); /* CONSTRAINT 'END1' */
|
|
VERIFY_ASSERT(&cn == &endNode);
|
|
foundEndNode = true;
|
|
}
|
|
if (cn.hasControlKind(ckReturn)) {
|
|
VERIFY_ASSERT(!foundReturnNode); /* CONSTRAINT 'RETURN1' */
|
|
VERIFY_ASSERT(&cn == returnNode);
|
|
foundReturnNode = true;
|
|
}
|
|
}
|
|
VERIFY_ASSERT(foundBeginNode); /* CONSTRAINT 'BEGIN1' */
|
|
VERIFY_ASSERT(foundEndNode); /* CONSTRAINT 'END1' */
|
|
|
|
|
|
// following only the forward edges, mark every reached node, starting with the begin node
|
|
ControlNode **stack = new ControlNode *[controlNodeCount];
|
|
ControlNode **sp = stack;
|
|
*sp++ = &beginNode;
|
|
Uint32 markedCount = 0;
|
|
while (sp != stack) {
|
|
ControlNode *n = *--sp;
|
|
connectedSearchMark[n->dfsNum] = 1; // 'marked'
|
|
markedCount++;
|
|
for (ControlEdge *s = n->getSuccessorsBegin(); s != n->getSuccessorsEnd(); s++) {
|
|
if (n->dfsNum < s->getTarget().dfsNum) { // a forward edge
|
|
if (connectedSearchMark[s->getTarget().dfsNum] == ControlNode::unmarked) {
|
|
connectedSearchMark[s->getTarget().dfsNum] = ControlNode::unvisited;
|
|
// so that this doesn't get pushed twice
|
|
*sp++ = &s->getTarget();
|
|
assert(sp < &stack[controlNodeCount]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// now assert that every node on the graph was marked
|
|
if (markedCount != controlNodeCount)
|
|
VERIFY_ASSERT(false);
|
|
for (cni = controlNodes.begin(); !controlNodes.done(cni); cni = controlNodes.advance(cni))
|
|
{
|
|
ControlNode &cn = controlNodes.get(cni);
|
|
VERIFY_ASSERT(connectedSearchMark[cn.dfsNum] == 1); /* CONSTRAINT 'CONNECTED1' */
|
|
connectedSearchMark[cn.dfsNum] = ControlNode::unmarked; // prepare for the next search, below
|
|
}
|
|
|
|
// likewise, but starting with the end node and reach back through all the predecessor links
|
|
markedCount = 0;
|
|
sp = stack;
|
|
*sp++ = &endNode;
|
|
while (sp != stack) {
|
|
ControlNode *n = *--sp;
|
|
connectedSearchMark[n->dfsNum] = 1; // 'marked'
|
|
markedCount++;
|
|
const DoublyLinkedList<ControlEdge> &nPredecessors = n->getPredecessors();
|
|
for (DoublyLinkedList<ControlEdge>::iterator predi = nPredecessors.begin();
|
|
!nPredecessors.done(predi);
|
|
predi = nPredecessors.advance(predi)) {
|
|
ControlEdge &e = nPredecessors.get(predi);
|
|
if (connectedSearchMark[e.getSource().dfsNum] == ControlNode::unmarked) {
|
|
connectedSearchMark[e.getSource().dfsNum] = ControlNode::unvisited;
|
|
*sp++ = &e.getSource();
|
|
assert(sp < &stack[controlNodeCount]);
|
|
}
|
|
}
|
|
}
|
|
// again, assert that every node was marked
|
|
if (markedCount != controlNodeCount)
|
|
VERIFY_ASSERT(false);
|
|
for (cni = controlNodes.begin(); !controlNodes.done(cni); cni = controlNodes.advance(cni))
|
|
{
|
|
ControlNode &cn = controlNodes.get(cni);
|
|
VERIFY_ASSERT(connectedSearchMark[cn.dfsNum] == 1); /* CONSTRAINT 'CONNECTED2' */
|
|
connectedSearchMark[cn.dfsNum] = ControlNode::unmarked; // prepare for the next search, below
|
|
}
|
|
|
|
// we do a recursive search on all the forward, return and exception edges to spot cycles therein
|
|
SearchStackEntry<ControlEdge> *searchStack = new SearchStackEntry<ControlEdge>[controlNodeCount];
|
|
SearchStackEntry<ControlEdge> *stackEnd = searchStack + controlNodeCount;
|
|
SearchStackEntry<ControlEdge> *esp = searchStack;
|
|
|
|
// Prepare to visit the root.
|
|
ControlEdge *n = beginNode.getSuccessorsBegin();
|
|
ControlEdge *l = beginNode.getSuccessorsEnd();
|
|
|
|
while (true) {
|
|
if (n == l) {
|
|
// We're done with all successors between n and l, so number the
|
|
// source node (which is on the stack) and pop up one level.
|
|
// Finish when we've marked the root.
|
|
if (esp == searchStack)
|
|
break;
|
|
--esp;
|
|
n = esp->next;
|
|
l = esp->limit;
|
|
connectedSearchMark[n[-1].getTarget().dfsNum] = 1;
|
|
}
|
|
else {
|
|
// We still have to visit more successors between n and l. Visit the
|
|
// next successor and advance n.
|
|
// But - only visit successors if the edge is a forward, return or exception edge
|
|
if ((n->getSource().dfsNum < n->getTarget().dfsNum)
|
|
|| (n->getSource().hasControlKind(ckReturn) && n->getTarget().hasControlKind(ckEnd))
|
|
|| ((n->getSource().hasControlKind(ckExc)
|
|
|| n->getSource().hasControlKind(ckAExc)
|
|
|| n->getSource().hasControlKind(ckThrow))
|
|
&& (n->getTarget().hasControlKind(ckEnd) || n->getTarget().hasControlKind(ckCatch)))) {
|
|
ControlNode &node = n->getTarget();
|
|
n++;
|
|
if (connectedSearchMark[node.dfsNum] == ControlNode::unmarked) {
|
|
// Visit the successor, saving the current place on the stack.
|
|
connectedSearchMark[node.dfsNum] = ControlNode::unvisited;
|
|
assert(esp < stackEnd);
|
|
esp->next = n;
|
|
esp->limit = l;
|
|
esp++;
|
|
n = node.getSuccessorsBegin();
|
|
l = node.getSuccessorsEnd();
|
|
}
|
|
else
|
|
VERIFY_ASSERT(connectedSearchMark[node.dfsNum] == 1); /* CONSTRAINT 'CYCLES1' */
|
|
|
|
}
|
|
else
|
|
n++;
|
|
}
|
|
}
|
|
#ifndef WIN32 // ***** Visual C++ has a bug in the code for delete[].
|
|
delete[] searchStack;
|
|
#endif
|
|
|
|
|
|
// in order to prove that every primtive's inputs are available we calculate
|
|
// the reaching nodes for each node. Then if an input is not in the current node
|
|
// we need simply ask if it's in a reaching node instead.
|
|
|
|
|
|
for (cni = controlNodes.begin(); !controlNodes.done(cni); cni = controlNodes.advance(cni))
|
|
{
|
|
ControlNode &cn = controlNodes.get(cni);
|
|
connectedSearchMark[cn.dfsNum] = ControlNode::unmarked;
|
|
}
|
|
|
|
sp = stack;
|
|
*sp++ = &beginNode;
|
|
reachingSet[beginNode.dfsNum] = new FastBitSet(controlNodeCount);
|
|
while (sp != stack) {
|
|
ControlNode *n = *--sp;
|
|
reachingSet[n->dfsNum]->set(n->dfsNum); // reaching ourselves is o.k. and this is the input to the successors
|
|
connectedSearchMark[n->dfsNum] = 1; // mark as having been processed
|
|
for (ControlEdge *s = n->getSuccessorsBegin(); s != n->getSuccessorsEnd(); s++) {
|
|
if (connectedSearchMark[s->getTarget().dfsNum] == ControlNode::unmarked) { // not been processed, ever simply set it to the current
|
|
reachingSet[s->getTarget().dfsNum] = new FastBitSet(*reachingSet[n->dfsNum]);
|
|
connectedSearchMark[s->getTarget().dfsNum] = ControlNode::unvisited;
|
|
*sp++ = &s->getTarget();
|
|
assert(sp < &stack[controlNodeCount]);
|
|
}
|
|
else {
|
|
FastBitSet *old = new FastBitSet(*reachingSet[s->getTarget().dfsNum]);
|
|
*reachingSet[s->getTarget().dfsNum] &= *reachingSet[n->dfsNum]; // we intersect because we want pessimistic data
|
|
if (*old != *reachingSet[s->getTarget().dfsNum]) { // if we have new data...
|
|
if (connectedSearchMark[s->getTarget().dfsNum] != ControlNode::unvisited) { // ...and not already scheduled for visiting
|
|
connectedSearchMark[s->getTarget().dfsNum] = ControlNode::unvisited;
|
|
*sp++ = &s->getTarget(); // then add it
|
|
assert(sp < &stack[controlNodeCount]);
|
|
}
|
|
}
|
|
delete old; // REMIND - better would've been an & operator that returned a 'changed' flag
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
for (cni = controlNodes.begin(); !controlNodes.done(cni); cni = controlNodes.advance(cni))
|
|
{
|
|
ControlNode &cn = controlNodes.get(cni);
|
|
fprintf(stderr, "For ControlNode N%d ", cn.dfsNum);
|
|
reachingSet[cn.dfsNum]->printPretty(stderr);
|
|
}
|
|
*/
|
|
|
|
delete stack;
|
|
|
|
// ask each control node to validate itself
|
|
|
|
for (cni = controlNodes.begin(); !controlNodes.done(cni); cni = controlNodes.advance(cni))
|
|
{
|
|
ControlNode &cn = controlNodes.get(cni);
|
|
cn.validate(reachingSet);
|
|
delete reachingSet[cn.dfsNum];
|
|
}
|
|
|
|
delete reachingSet;
|
|
delete connectedSearchMark;
|
|
|
|
UT_LOG(GraphVerifier, PR_LOG_ALWAYS, ("\n*** Verify succeeded \n\n", this));
|
|
|
|
// REMIND - assert(foundReturnNode == (method != void_return)); how to get the return type ?
|
|
// REMIND - assert that all successors/predecessors are in this graph ?
|
|
|
|
}
|
|
|
|
void ControlNode::validate(FastBitSet **reachingSet)
|
|
{
|
|
// check that all contained primitives have this as their container and that all inputs
|
|
// to each primtive are available (either precede their use in this node, or come from
|
|
// a reaching node)
|
|
DoublyLinkedList<Primitive>::iterator pi;
|
|
|
|
if (!primitives.empty()) {
|
|
for (pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
VERIFY_ASSERT(prim.getContainer() == this);
|
|
prim.mark = false;
|
|
}
|
|
for (pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
VERIFY_ASSERT(prim.getContainer() == this);
|
|
for (DataConsumer *input = prim.getInputsBegin(); input != prim.getInputsEnd(); input++) {
|
|
if (input->isVariable()) {
|
|
if (input->getVariable().getContainer() == this) {
|
|
VERIFY_ASSERT(input->getVariable().mark);
|
|
}
|
|
else {
|
|
VERIFY_ASSERT(reachingSet[dfsNum]->test(input->getVariable().getContainer()->dfsNum));
|
|
}
|
|
}
|
|
}
|
|
prim.mark = true;
|
|
}
|
|
}
|
|
|
|
// count the number of incoming/outgoing exception, normal and backward (etc) edges
|
|
|
|
Uint32 incomingExceptionEdges = 0, incomingNormalEdges = 0, incomingBackwardEdges = 0, incomingReturnEdges = 0;
|
|
Uint32 outgoingExceptionEdges = 0, outgoingNormalEdges = 0, outgoingEndEdges = 0;
|
|
|
|
if (!predecessors.empty()) {
|
|
for (DoublyLinkedList<ControlEdge>::iterator predi = predecessors.begin();
|
|
!predecessors.done(predi);
|
|
predi = predecessors.advance(predi)) {
|
|
ControlEdge &e = predecessors.get(predi);
|
|
if (e.getSource().dfsNum > dfsNum) incomingBackwardEdges++;
|
|
if (e.getSource().hasControlKind(ckReturn))
|
|
incomingReturnEdges++;
|
|
else
|
|
if (e.getSource().hasControlKind(ckThrow))
|
|
incomingExceptionEdges++;
|
|
else
|
|
if (e.getSource().hasControlKind(ckExc) || e.getSource().hasControlKind(ckAExc)) // the first successor from an Exc node is normal
|
|
if (&e.getSource().getSuccessorsBegin()->getTarget() == this)
|
|
incomingNormalEdges++;
|
|
else
|
|
incomingExceptionEdges++;
|
|
else
|
|
incomingNormalEdges++;
|
|
}
|
|
}
|
|
for (ControlEdge *successor = successorsBegin; successor != successorsEnd; successor++) {
|
|
if (successor->getTarget().hasControlKind(ckCatch))
|
|
outgoingExceptionEdges++;
|
|
else
|
|
if (successor->getTarget().hasControlKind(ckEnd))
|
|
outgoingEndEdges++;
|
|
else
|
|
outgoingNormalEdges++;
|
|
}
|
|
|
|
if (!hasExceptionInputs(controlKind)) VERIFY_ASSERT(incomingExceptionEdges == 0); /* CONSTRAINT 'BEGIN3' */
|
|
if (!hasNormalInputs(controlKind)) VERIFY_ASSERT(incomingNormalEdges == 0); /* CONSTRAINT 'BEGIN3', 'END2' */
|
|
if (!hasExceptionOutgoingEdges(controlKind)) VERIFY_ASSERT(outgoingExceptionEdges == 0); /* CONSTRAINT 'END3', 'EDGE2' */
|
|
if (!hasNormalOutgoingEdges(controlKind)) VERIFY_ASSERT(outgoingNormalEdges == 0); /* CONSTRAINT 'END3' */
|
|
if (hasOneNormalOutgoingEdge(controlKind)) VERIFY_ASSERT(outgoingNormalEdges == 1); /* CONSTRAINT 'BEGIN2' */
|
|
if (controlKind != ckEnd) VERIFY_ASSERT(incomingReturnEdges == 0); /* CONSTRAINT 'BEGIN3', 'END2' */
|
|
if (controlKind == ckReturn) VERIFY_ASSERT(outgoingEndEdges == 1); /* CONSTRAINT 'RETURN2' */
|
|
else
|
|
if ((controlKind != ckAExc)
|
|
&& (controlKind != ckExc)
|
|
&& (controlKind != ckThrow)) VERIFY_ASSERT(outgoingEndEdges == 0); /* CONSTRAINT 'END3', 'RETURN2' */
|
|
if (controlKind != ckAExc) VERIFY_ASSERT(incomingBackwardEdges == 0); /* CONSTRAINT 'EDGE1' */
|
|
|
|
if ((controlKind != ckBegin) && (controlKind != ckEnd) && (controlKind != ckCatch)) {
|
|
Uint32 totalOutgoingEdges = outgoingExceptionEdges + outgoingNormalEdges + outgoingEndEdges;
|
|
ControlNode &theSuccessorNode = successorsBegin->getTarget();
|
|
if ((totalOutgoingEdges == 1)
|
|
&& (!theSuccessorNode.hasControlKind(ckEnd))
|
|
&& (!theSuccessorNode.hasControlKind(ckCatch))) {
|
|
// this node has a single output, prove that it's successor has more than a single input
|
|
const DoublyLinkedList<ControlEdge> &theSuccessorsPredecessors = theSuccessorNode.getPredecessors();
|
|
DoublyLinkedList<ControlEdge>::iterator predi = theSuccessorsPredecessors.begin();
|
|
predi = theSuccessorsPredecessors.advance(predi);
|
|
VERIFY_ASSERT(!theSuccessorsPredecessors.done(predi)); /* CONSTRAINT 'COALESCE1' */
|
|
}
|
|
}
|
|
|
|
// now perform control-kind specific primitive checks...
|
|
switch (controlKind) {
|
|
case ckNone : // shouldn't have any of these
|
|
VERIFY_ASSERT(false);
|
|
break;
|
|
case ckBegin : // all primitives are Args
|
|
{
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
VERIFY_ASSERT(prim.hasCategory(pcArg));
|
|
}
|
|
// REMIND - assert that the correct number of args is here (does it equal beginExtra.nArguments ?)
|
|
// REMIND - assert that a memory arg is present ?
|
|
}
|
|
break;
|
|
case ckEnd : // only a result memory primitive (and maybe a phi for it)
|
|
{
|
|
bool foundTheResult = false;
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
if (prim.hasOperation(poResult_M)) {
|
|
VERIFY_ASSERT(!foundTheResult); // insist on only one such
|
|
foundTheResult = true;
|
|
}
|
|
else
|
|
VERIFY_ASSERT(prim.hasOperation(poPhi_M));
|
|
}
|
|
VERIFY_ASSERT(foundTheResult);
|
|
}
|
|
break;
|
|
case ckBlock : // no exception raising primitives, no control flow primitives
|
|
{
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
VERIFY_ASSERT(!prim.hasFormat(pfControl));
|
|
VERIFY_ASSERT(!prim.canRaiseException());
|
|
}
|
|
}
|
|
break;
|
|
case ckIf : // exactly two exits
|
|
{ // no exception raising primitives, no control flow primitives other than the one If
|
|
VERIFY_ASSERT(successorsEnd == (successorsBegin + 2));
|
|
Primitive *theIf = NULL;
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
if (prim.hasFormat(pfControl)) {
|
|
if (prim.hasCategory(pcIfCond)) {
|
|
VERIFY_ASSERT(theIf == NULL);
|
|
theIf = &prim;
|
|
}
|
|
else
|
|
VERIFY_ASSERT(false);
|
|
}
|
|
VERIFY_ASSERT(!prim.canRaiseException());
|
|
}
|
|
VERIFY_ASSERT(theIf != NULL);
|
|
// the source for the if condition must be in the same control node
|
|
VERIFY_ASSERT(theIf->nthInputVariable(0).getContainer() == this);
|
|
}
|
|
break;
|
|
case ckSwitch : // no exception raising primitives, no control flow primitives other than the one Switch
|
|
{
|
|
bool foundTheSwitch = false;
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
if (prim.hasFormat(pfControl)) {
|
|
if (prim.hasCategory(pcSwitch)) {
|
|
VERIFY_ASSERT(!foundTheSwitch);
|
|
foundTheSwitch = true;
|
|
}
|
|
else
|
|
VERIFY_ASSERT(false);
|
|
}
|
|
VERIFY_ASSERT(!prim.canRaiseException());
|
|
}
|
|
VERIFY_ASSERT(foundTheSwitch);
|
|
}
|
|
break;
|
|
case ckAExc : // no exception raising primitives, no control nodes
|
|
{
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
VERIFY_ASSERT(!prim.hasFormat(pfControl));
|
|
VERIFY_ASSERT(!prim.canRaiseException());
|
|
}
|
|
}
|
|
break;
|
|
case ckThrow : // contains no control primitives
|
|
{
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
VERIFY_ASSERT(!prim.hasFormat(pfControl));
|
|
}
|
|
}
|
|
break;
|
|
case ckExc : // contains only one exception raising primitive, no control primitives
|
|
{
|
|
bool foundTheExceptionPrimitive = false;
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
VERIFY_ASSERT(!prim.hasFormat(pfControl));
|
|
if (prim.canRaiseException()) {
|
|
VERIFY_ASSERT(!foundTheExceptionPrimitive);
|
|
foundTheExceptionPrimitive = true;
|
|
}
|
|
}
|
|
if (!foundTheExceptionPrimitive) {
|
|
printPretty(UT_LOG_MODULE(GraphVerifier), 0);
|
|
}
|
|
VERIFY_ASSERT(foundTheExceptionPrimitive);
|
|
}
|
|
break;
|
|
case ckCatch : // at most one primitive, must be a catch (with optional phi's), no control primitives
|
|
{
|
|
bool foundTheCatch = false;
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
VERIFY_ASSERT(!prim.hasFormat(pfControl));
|
|
if (prim.hasCategory(pcCatch)) {
|
|
VERIFY_ASSERT(!foundTheCatch);
|
|
foundTheCatch = true;
|
|
}
|
|
else
|
|
VERIFY_ASSERT(prim.hasCategory(pcPhi));
|
|
}
|
|
VERIFY_ASSERT(foundTheCatch);
|
|
}
|
|
break;
|
|
case ckReturn : // no exception raising primitives, no control flow primitives
|
|
{
|
|
for (DoublyLinkedList<Primitive>::iterator pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
VERIFY_ASSERT(!prim.hasFormat(pfControl));
|
|
VERIFY_ASSERT(!prim.canRaiseException());
|
|
}
|
|
}
|
|
break;
|
|
default :
|
|
VERIFY_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
// make sure that all a primitive's inputs come from primitives outside of this node
|
|
// or one that is before the primitive within the control node
|
|
|
|
|
|
// now ask each contained primitive to validate itself
|
|
|
|
for (pi = primitives.begin();
|
|
!primitives.done(pi);
|
|
pi = primitives.advance(pi)) {
|
|
Primitive& prim = primitives.get(pi);
|
|
prim.validate();
|
|
}
|
|
|
|
}
|
|
|
|
void DataNode::validate()
|
|
{
|
|
InputConstraintPattern theConstraint = inputConstraintPatterns[operation];
|
|
|
|
int inputIndex = 0;
|
|
DataConsumer *input = inputsBegin;
|
|
if (input == NULL) {
|
|
if (theConstraint.nInputConstraints != 0)
|
|
printPretty(UT_LOG_MODULE(GraphVerifier), 0);
|
|
VERIFY_ASSERT(theConstraint.nInputConstraints == 0);
|
|
}
|
|
else
|
|
while (true) {
|
|
|
|
// something about tuples and exceptions ????
|
|
|
|
VERIFY_ASSERT((theConstraint.inputConstraints[inputIndex].kind == vkVoid)
|
|
|| (input->getKind() == theConstraint.inputConstraints[inputIndex].kind));
|
|
/*
|
|
if (! ((theConstraint.inputConstraints[inputIndex].origin == aoEither)
|
|
|| (input->isVariable() == (theConstraint.inputConstraints[inputIndex].origin == aoVariable))) )
|
|
printPretty(UT_LOG_MODULE(GraphVerifier), 0);
|
|
*/
|
|
VERIFY_ASSERT((theConstraint.inputConstraints[inputIndex].origin == aoEither)
|
|
|| (input->isVariable() == (theConstraint.inputConstraints[inputIndex].origin == aoVariable)));
|
|
inputIndex++;
|
|
input++;
|
|
if (inputIndex == theConstraint.nInputConstraints) {
|
|
if (input == inputsEnd)
|
|
break; // all's well, and we ended together
|
|
else
|
|
if (theConstraint.repeat)
|
|
inputIndex--; // keep matching on the last pattern
|
|
else
|
|
VERIFY_ASSERT(false); // there are no more patterns, but there are more inputs
|
|
}
|
|
else {
|
|
// if we still have more patterns, make sure there are inputs to match OR that we're on
|
|
// the 'zero or more times' repeatable last pattern and in which case, break out of the loop.
|
|
if (input == inputsEnd) {
|
|
VERIFY_ASSERT((inputIndex == (theConstraint.nInputConstraints - 1)) && theConstraint.repeat);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void PrimConst::validate()
|
|
{
|
|
InputConstraintPattern theConstraint = getInputConstraintPattern();
|
|
VERIFY_ASSERT(theConstraint.inputConstraints[0].origin == aoConstant);
|
|
|
|
if (getKind() != theConstraint.inputConstraints[0].kind) {
|
|
printPretty(UT_LOG_MODULE(GraphVerifier), 0);
|
|
}
|
|
VERIFY_ASSERT(getKind() == theConstraint.inputConstraints[0].kind);
|
|
}
|
|
|
|
|
|
#endif // DEBUG
|