Skip to content

Commit

Permalink
Bug 1084612 - IonMonkey: Reduce the complexity of the assertion of th…
Browse files Browse the repository at this point in the history
…e graph coherency. r=sunfish
  • Loading branch information
nbp committed Nov 18, 2014
1 parent 52aa411 commit e460d51
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 21 deletions.
90 changes: 69 additions & 21 deletions js/src/jit/IonAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1776,28 +1776,73 @@ CheckPredecessorImpliesSuccessor(MBasicBlock *A, MBasicBlock *B)
return false;
}

static bool
CheckOperandImpliesUse(MNode *n, MDefinition *operand)
{
MOZ_ASSERT(!operand->isDiscarded());
MOZ_ASSERT(operand->block() != nullptr);
// If you have issues with the usesBalance assertions, then define the macro
// _DEBUG_CHECK_OPERANDS_USES_BALANCE to spew information on the error output.
// This output can then be processed with the following awk script to filter and
// highlight which checks are missing or if there is an unexpected operand /
// use.
//
// define _DEBUG_CHECK_OPERANDS_USES_BALANCE 1
/*
for (MUseIterator i = operand->usesBegin(); i != operand->usesEnd(); i++) {
if (i->consumer() == n)
return true;
$ ./js 2>stderr.log
$ gawk '
/^==Check/ { context = ""; state = $2; }
/^[a-z]/ { context = context "\n\t" $0; }
/^==End/ {
if (state == "Operand") {
list[context] = list[context] - 1;
} else if (state == "Use") {
list[context] = list[context] + 1;
}
}
return false;
END {
for (ctx in list) {
if (list[ctx] > 0) {
print "Missing operand check", ctx, "\n"
}
if (list[ctx] < 0) {
print "Missing use check", ctx, "\n"
}
};
}' < stderr.log
*/

static void
CheckOperand(const MNode *consumer, const MUse *use, int32_t *usesBalance)
{
MOZ_ASSERT(use->hasProducer());
MDefinition *producer = use->producer();
MOZ_ASSERT(!producer->isDiscarded());
MOZ_ASSERT(producer->block() != nullptr);
MOZ_ASSERT(use->consumer() == consumer);
#ifdef _DEBUG_CHECK_OPERANDS_USES_BALANCE
fprintf(stderr, "==Check Operand\n");
use->producer()->dump(stderr);
fprintf(stderr, " index: %zu\n", use->consumer()->indexOf(use));
use->consumer()->dump(stderr);
fprintf(stderr, "==End\n");
#endif
--*usesBalance;
}

static bool
CheckUseImpliesOperand(MDefinition *def, MUse *use)
static void
CheckUse(const MDefinition *producer, const MUse *use, int32_t *usesBalance)
{
MOZ_ASSERT(!use->consumer()->block()->isDead());
MOZ_ASSERT_IF(use->consumer()->isDefinition(),
!use->consumer()->toDefinition()->isDiscarded());
MOZ_ASSERT(use->consumer()->block() != nullptr);

return use->consumer()->getOperand(use->index()) == def;
MOZ_ASSERT(use->consumer()->getOperand(use->index()) == producer);
#ifdef _DEBUG_CHECK_OPERANDS_USES_BALANCE
fprintf(stderr, "==Check Use\n");
use->producer()->dump(stderr);
fprintf(stderr, " index: %zu\n", use->consumer()->indexOf(use));
use->consumer()->dump(stderr);
fprintf(stderr, "==End\n");
#endif
++*usesBalance;
}
#endif // DEBUG

Expand All @@ -1821,6 +1866,7 @@ jit::AssertBasicGraphCoherency(MIRGraph &graph)

// Assert successor and predecessor list coherency.
uint32_t count = 0;
int32_t usesBalance = 0;
for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
count++;

Expand Down Expand Up @@ -1848,10 +1894,8 @@ jit::AssertBasicGraphCoherency(MIRGraph &graph)
// the entry resume point because we are still storing resume points
// in the InlinePropertyTable.
MOZ_ASSERT_IF(iter->instruction(), iter->instruction()->block() == *block);
for (uint32_t i = 0, e = iter->numOperands(); i < e; i++) {
MOZ_ASSERT(iter->getUseFor(i)->hasProducer());
MOZ_ASSERT(CheckOperandImpliesUse(*iter, iter->getOperand(i)));
}
for (uint32_t i = 0, e = iter->numOperands(); i < e; i++)
CheckOperand(*iter, iter->getUseFor(i), &usesBalance);
}
for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
MOZ_ASSERT(phi->numOperands() == block->numPredecessors());
Expand All @@ -1872,9 +1916,9 @@ jit::AssertBasicGraphCoherency(MIRGraph &graph)

// Assert that use chains are valid for this instruction.
for (uint32_t i = 0, end = iter->numOperands(); i < end; i++)
MOZ_ASSERT(CheckOperandImpliesUse(*iter, iter->getOperand(i)));
CheckOperand(*iter, iter->getUseFor(i), &usesBalance);
for (MUseIterator use(iter->usesBegin()); use != iter->usesEnd(); use++)
MOZ_ASSERT(CheckUseImpliesOperand(*iter, *use));
CheckUse(*iter, *use, &usesBalance);

if (iter->isInstruction()) {
if (MResumePoint *resume = iter->toInstruction()->resumePoint()) {
Expand All @@ -1888,17 +1932,21 @@ jit::AssertBasicGraphCoherency(MIRGraph &graph)
MOZ_ASSERT(!iter->hasLiveDefUses());
}

// The control instruction is not visited by the MDefinitionIterator.
MControlInstruction *control = block->lastIns();
MOZ_ASSERT(control->block() == *block);
MOZ_ASSERT(!control->hasUses());
MOZ_ASSERT(control->type() == MIRType_None);
MOZ_ASSERT(!control->isDiscarded());
MOZ_ASSERT(!control->isRecoveredOnBailout());
MOZ_ASSERT(control->resumePoint() == nullptr);
for (uint32_t i = 0, end = control->numOperands(); i < end; ++i)
MOZ_ASSERT(CheckOperandImpliesUse(control, control->getOperand(i)));
for (uint32_t i = 0, end = control->numOperands(); i < end; i++)
CheckOperand(control, control->getUseFor(i), &usesBalance);
}

// In case issues, see the _DEBUG_CHECK_OPERANDS_USES_BALANCE macro above.
MOZ_ASSERT(usesBalance <= 0, "More use checks than operand checks");
MOZ_ASSERT(usesBalance >= 0, "More operand checks than use checks");
MOZ_ASSERT(graph.numBlocks() == count);
#endif
}
Expand Down
3 changes: 3 additions & 0 deletions js/src/jit/MIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@ class MNode : public TempObject
virtual void dump() const = 0;

protected:
// Need visibility on getUseFor to avoid O(n^2) complexity.
friend void AssertBasicGraphCoherency(MIRGraph &graph);

// Gets the MUse corresponding to given operand.
virtual MUse *getUseFor(size_t index) = 0;
virtual const MUse *getUseFor(size_t index) const = 0;
Expand Down

0 comments on commit e460d51

Please sign in to comment.