Bug 943449 - IonMonkey: Introduce a new idiom for dumping routines: dump(). r=nbp
authorDan Gohman <sunfish@google.com>
Tue, 26 Nov 2013 11:22:58 -0800
changeset 157957 4b627d104594af5c0edfa43343cdf745b93574e2
parent 157956 f2ed1e244513e952c6a800874577263c9d6b51a0
child 157958 c81e58d7c31d625c858c488c29b60791e63964bc
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersnbp
bugs943449
milestone28.0a1
Bug 943449 - IonMonkey: Introduce a new idiom for dumping routines: dump(). r=nbp
js/src/jit/BacktrackingAllocator.cpp
js/src/jit/C1Spewer.cpp
js/src/jit/IonAnalysis.cpp
js/src/jit/IonAnalysis.h
js/src/jit/JSONSpewer.cpp
js/src/jit/LIR.cpp
js/src/jit/LIR.h
js/src/jit/LiveRangeAllocator.cpp
js/src/jit/LiveRangeAllocator.h
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/MIRGraph.cpp
js/src/jit/MIRGraph.h
js/src/jit/RangeAnalysis.cpp
js/src/jit/RangeAnalysis.h
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/BacktrackingAllocator.h"
-#include "jsprf.h"
 #include "jit/BitSet.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
 bool
@@ -71,43 +70,16 @@ BacktrackingAllocator::init()
         AllocatedRange range(hotcodeInterval, hotcodeInterval->getRange(i));
         if (!hotcode.insert(range))
             return false;
     }
 
     return true;
 }
 
-static inline const char *
-IntervalString(const LiveInterval *interval)
-{
-#ifdef DEBUG
-    if (!interval->numRanges())
-        return " empty";
-
-    // Not reentrant!
-    static char buf[1000];
-
-    char *cursor = buf;
-    char *end = cursor + sizeof(buf);
-
-    for (size_t i = 0; i < interval->numRanges(); i++) {
-        const LiveInterval::Range *range = interval->getRange(i);
-        int n = JS_snprintf(cursor, end - cursor, " [%u,%u>", range->from.pos(), range->to.pos());
-        if (n < 0)
-            return " ???";
-        cursor += n;
-    }
-
-    return buf;
-#else
-    return " ???";
-#endif
-}
-
 bool
 BacktrackingAllocator::go()
 {
     IonSpew(IonSpew_RegAlloc, "Beginning register allocation");
 
     IonSpew(IonSpew_RegAlloc, "Beginning liveness analysis");
     if (!buildLivenessInfo())
         return false;
@@ -418,17 +390,17 @@ BacktrackingAllocator::groupAndQueueRegi
 static const size_t MAX_ATTEMPTS = 2;
 
 bool
 BacktrackingAllocator::processInterval(LiveInterval *interval)
 {
     if (IonSpewEnabled(IonSpew_RegAlloc)) {
         IonSpew(IonSpew_RegAlloc, "Allocating v%u [priority %lu] [weight %lu]: %s",
                 interval->vreg(), computePriority(interval), computeSpillWeight(interval),
-                IntervalString(interval));
+                interval->rangesToString());
     }
 
     // An interval can be processed by doing any of the following:
     //
     // - Assigning the interval a register. The interval cannot overlap any
     //   other interval allocated for that physical register.
     //
     // - Spilling the interval, provided it has no register uses.
@@ -736,17 +708,17 @@ BacktrackingAllocator::tryAllocateRegist
     return true;
 }
 
 bool
 BacktrackingAllocator::evictInterval(LiveInterval *interval)
 {
     if (IonSpewEnabled(IonSpew_RegAlloc)) {
         IonSpew(IonSpew_RegAlloc, "Evicting interval v%u: %s",
-                interval->vreg(), IntervalString(interval));
+                interval->vreg(), interval->rangesToString());
     }
 
     JS_ASSERT(interval->getAllocation()->isRegister());
 
     AnyRegister reg(interval->getAllocation()->toRegister());
     PhysicalRegister &physical = registers[reg.code()];
     JS_ASSERT(physical.reg == reg && physical.allocatable);
 
@@ -789,19 +761,19 @@ BacktrackingAllocator::distributeUses(Li
 }
 
 bool
 BacktrackingAllocator::split(LiveInterval *interval,
                              const LiveIntervalVector &newIntervals)
 {
     if (IonSpewEnabled(IonSpew_RegAlloc)) {
         IonSpew(IonSpew_RegAlloc, "splitting interval v%u %s into:",
-                interval->vreg(), IntervalString(interval));
+                interval->vreg(), interval->rangesToString());
         for (size_t i = 0; i < newIntervals.length(); i++)
-            IonSpew(IonSpew_RegAlloc, "    %s", IntervalString(newIntervals[i]));
+            IonSpew(IonSpew_RegAlloc, "    %s", newIntervals[i]->rangesToString());
     }
 
     JS_ASSERT(newIntervals.length() >= 2);
 
     // Find the earliest interval in the new list.
     LiveInterval *first = newIntervals[0];
     for (size_t i = 1; i < newIntervals.length(); i++) {
         if (newIntervals[i]->start() < first->start())
@@ -1239,27 +1211,27 @@ BacktrackingAllocator::dumpLiveness()
             fprintf(stderr, "\n");
         }
     }
 
     fprintf(stderr, "\nLive Ranges:\n\n");
 
     for (size_t i = 0; i < AnyRegister::Total; i++)
         if (registers[i].allocatable)
-            fprintf(stderr, "reg %s: %s\n", AnyRegister::FromCode(i).name(), IntervalString(fixedIntervals[i]));
+            fprintf(stderr, "reg %s: %s\n", AnyRegister::FromCode(i).name(), fixedIntervals[i]->rangesToString());
 
     // Virtual register number 0 is unused.
     JS_ASSERT(vregs[0u].numIntervals() == 0);
     for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
         fprintf(stderr, "v%lu:", static_cast<unsigned long>(i));
         VirtualRegister &vreg = vregs[i];
         for (size_t j = 0; j < vreg.numIntervals(); j++) {
             if (j)
                 fprintf(stderr, " *");
-            fprintf(stderr, "%s", IntervalString(vreg.getInterval(j)));
+            fprintf(stderr, "%s", vreg.getInterval(j)->rangesToString());
         }
         fprintf(stderr, "\n");
     }
 
     fprintf(stderr, "\n");
 #endif // DEBUG
 }
 
@@ -1267,20 +1239,20 @@ BacktrackingAllocator::dumpLiveness()
 struct BacktrackingAllocator::PrintLiveIntervalRange
 {
     void operator()(const AllocatedRange &item)
     {
         if (item.range == item.interval->getRange(0)) {
             if (item.interval->hasVreg())
                 fprintf(stderr, "  v%u: %s\n",
                        item.interval->vreg(),
-                       IntervalString(item.interval));
+                       item.interval->rangesToString());
             else
                 fprintf(stderr, "  fixed: %s\n",
-                       IntervalString(item.interval));
+                       item.interval->rangesToString());
         }
     }
 };
 #endif
 
 void
 BacktrackingAllocator::dumpAllocations()
 {
@@ -1291,17 +1263,17 @@ BacktrackingAllocator::dumpAllocations()
     JS_ASSERT(vregs[0u].numIntervals() == 0);
     for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
         fprintf(stderr, "v%lu:", static_cast<unsigned long>(i));
         VirtualRegister &vreg = vregs[i];
         for (size_t j = 0; j < vreg.numIntervals(); j++) {
             if (j)
                 fprintf(stderr, " *");
             LiveInterval *interval = vreg.getInterval(j);
-            fprintf(stderr, "%s :: %s", IntervalString(interval), interval->getAllocation()->toString());
+            fprintf(stderr, "%s :: %s", interval->rangesToString(), interval->getAllocation()->toString());
         }
         fprintf(stderr, "\n");
     }
 
     fprintf(stderr, "\n");
 
     for (size_t i = 0; i < AnyRegister::Total; i++) {
         if (registers[i].allocatable) {
--- a/js/src/jit/C1Spewer.cpp
+++ b/js/src/jit/C1Spewer.cpp
@@ -101,17 +101,17 @@ DumpDefinition(FILE *fp, MDefinition *de
     fprintf(fp, " <|@\n");
 }
 
 static void
 DumpLIR(FILE *fp, LInstruction *ins)
 {
     fprintf(fp, "      ");
     fprintf(fp, "%d ", ins->id());
-    ins->print(fp);
+    ins->dump(fp);
     fprintf(fp, " <|@\n");
 }
 
 void
 C1Spewer::spewIntervals(FILE *fp, LinearScanAllocator *regalloc, LInstruction *ins, size_t &nextId)
 {
     for (size_t k = 0; k < ins->numDefs(); k++) {
         uint32_t id = ins->getDef(k)->virtualRegister();
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1916,16 +1916,22 @@ void
 LinearSum::dump(FILE *fp) const
 {
     Sprinter sp(GetIonContext()->cx);
     sp.init();
     print(sp);
     fprintf(fp, "%s\n", sp.string());
 }
 
+void
+LinearSum::dump() const
+{
+    dump(stderr);
+}
+
 static bool
 AnalyzePoppedThis(JSContext *cx, types::TypeObject *type,
                   MDefinition *thisValue, MInstruction *ins, bool definitelyExecuted,
                   HandleObject baseobj,
                   Vector<types::TypeNewScript::Initializer> *initializerList,
                   Vector<PropertyName *> *accessedProperties,
                   bool *phandled)
 {
--- a/js/src/jit/IonAnalysis.h
+++ b/js/src/jit/IonAnalysis.h
@@ -116,16 +116,17 @@ class LinearSum
     bool add(int32_t constant);
 
     int32_t constant() const { return constant_; }
     size_t numTerms() const { return terms_.length(); }
     LinearTerm term(size_t i) const { return terms_[i]; }
 
     void print(Sprinter &sp) const;
     void dump(FILE *) const;
+    void dump() const;
 
   private:
     Vector<LinearTerm, 2, IonAllocPolicy> terms_;
     int32_t constant_;
 };
 
 bool
 AnalyzeNewScriptProperties(JSContext *cx, HandleFunction fun,
--- a/js/src/jit/JSONSpewer.cpp
+++ b/js/src/jit/JSONSpewer.cpp
@@ -339,17 +339,17 @@ JSONSpewer::spewLIns(LInstruction *ins)
         return;
 
     beginObject();
 
     integerProperty("id", ins->id());
 
     property("opcode");
     fprintf(fp_, "\"");
-    ins->print(fp_);
+    ins->dump(fp_);
     fprintf(fp_, "\"");
 
     beginListProperty("defs");
     for (size_t i = 0; i < ins->numDefs(); i++)
         integerValue(ins->getDef(i)->virtualRegister());
     endList();
 
     endObject();
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -283,16 +283,22 @@ LAllocation::toString() const
         return buf;
       default:
         MOZ_ASSUME_UNREACHABLE("what?");
     }
 }
 #endif // DEBUG
 
 void
+LAllocation::dump() const
+{
+    fprintf(stderr, "%s\n", toString());
+}
+
+void
 LInstruction::printOperands(FILE *fp)
 {
     for (size_t i = 0, e = numOperands(); i < e; i++) {
         fprintf(fp, " (%s)", getOperand(i)->toString());
         if (i != numOperands() - 1)
             fprintf(fp, ",");
     }
 }
@@ -310,17 +316,17 @@ LInstruction::assignSnapshot(LSnapshot *
                 (void *)snapshot, (void *)this);
         printName(IonSpewFile);
         fprintf(IonSpewFile, ")\n");
     }
 #endif
 }
 
 void
-LInstruction::print(FILE *fp)
+LInstruction::dump(FILE *fp)
 {
     fprintf(fp, "{");
     for (size_t i = 0; i < numDefs(); i++) {
         PrintDefinition(fp, *getDef(i));
         if (i != numDefs() - 1)
             fprintf(fp, ", ");
     }
     fprintf(fp, "} <- ");
@@ -337,16 +343,22 @@ LInstruction::print(FILE *fp)
             if (i != numTemps() - 1)
                 fprintf(fp, ", ");
         }
         fprintf(fp, ")");
     }
 }
 
 void
+LInstruction::dump()
+{
+    return dump(stderr);
+}
+
+void
 LInstruction::initSafepoint(TempAllocator &alloc)
 {
     JS_ASSERT(!safepoint_);
     safepoint_ = new LSafepoint(alloc);
     JS_ASSERT(safepoint_);
 }
 
 bool
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -198,16 +198,18 @@ class LAllocation : public TempObject
         return bits_;
     }
 
 #ifdef DEBUG
     const char *toString() const;
 #else
     const char *toString() const { return "???"; }
 #endif
+
+    void dump() const;
 };
 
 class LUse : public LAllocation
 {
     static const uint32_t POLICY_BITS = 3;
     static const uint32_t POLICY_SHIFT = 0;
     static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
     static const uint32_t REG_BITS = 5;
@@ -670,17 +672,18 @@ class LInstruction
     void initSafepoint(TempAllocator &alloc);
 
     // For an instruction which has a MUST_REUSE_INPUT output, whether that
     // output register will be restored to its original value when bailing out.
     virtual bool recoversInput() const {
         return false;
     }
 
-    virtual void print(FILE *fp);
+    virtual void dump(FILE *fp);
+    void dump();
     static void printName(FILE *fp, Opcode op);
     virtual void printName(FILE *fp);
     virtual void printOperands(FILE *fp);
     virtual void printInfo(FILE *fp) { }
 
   public:
     // Opcode testing and casts.
 #   define LIROP(name)                                                      \
--- a/js/src/jit/LiveRangeAllocator.cpp
+++ b/js/src/jit/LiveRangeAllocator.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/LiveRangeAllocator.h"
 #include "mozilla/DebugOnly.h"
 #include "jit/BacktrackingAllocator.h"
 #include "jit/BitSet.h"
 #include "jit/LinearScan.h"
+#include "jsprf.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
 int
 Requirement::priority() const
@@ -854,8 +855,42 @@ LiveInterval::validateRanges()
 
         JS_ASSERT(range->from < range->to);
         JS_ASSERT_IF(prev, prev->to <= range->from);
         prev = range;
     }
 }
 
 #endif // DEBUG
+
+const char *
+LiveInterval::rangesToString() const
+{
+#ifdef DEBUG
+    if (!numRanges())
+        return " empty";
+
+    // Not reentrant!
+    static char buf[1000];
+
+    char *cursor = buf;
+    char *end = cursor + sizeof(buf);
+
+    for (size_t i = 0; i < numRanges(); i++) {
+        const LiveInterval::Range *range = getRange(i);
+        int n = JS_snprintf(cursor, end - cursor, " [%u,%u>", range->from.pos(), range->to.pos());
+        if (n < 0)
+            return " ???";
+        cursor += n;
+    }
+
+    return buf;
+#else
+    return " ???";
+#endif
+}
+
+void
+LiveInterval::dump()
+{
+    fprintf(stderr, "v%u: index=%u allocation=%s %s\n",
+            vreg(), index(), getAllocation()->toString(), rangesToString());
+}
--- a/js/src/jit/LiveRangeAllocator.h
+++ b/js/src/jit/LiveRangeAllocator.h
@@ -375,16 +375,22 @@ class LiveInterval
 
     UsePosition *usesBack() {
         return uses_.back();
     }
 
 #ifdef DEBUG
     void validateRanges();
 #endif
+
+    // Return a string describing the ranges in this LiveInterval. This is
+    // not re-entrant!
+    const char *rangesToString() const;
+
+    void dump();
 };
 
 /*
  * Represents all of the register allocation state associated with a virtual
  * register, including all associated intervals and pointers to relevant LIR
  * structures.
  */
 class VirtualRegister
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -276,16 +276,22 @@ void
 MDefinition::dump(FILE *fp) const
 {
     printName(fp);
     fprintf(fp, " = ");
     printOpcode(fp);
     fprintf(fp, "\n");
 }
 
+void
+MDefinition::dump() const
+{
+    dump(stderr);
+}
+
 size_t
 MDefinition::useCount() const
 {
     size_t count = 0;
     for (MUseIterator i(uses_.begin()); i != uses_.end(); i++)
         count++;
     return count;
 }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -332,16 +332,17 @@ class MDefinition : public MNode
     { }
 
     virtual Opcode op() const = 0;
     virtual const char *opName() const = 0;
     void printName(FILE *fp) const;
     static void PrintOpcodeName(FILE *fp, Opcode op);
     virtual void printOpcode(FILE *fp) const;
     void dump(FILE *fp) const;
+    void dump() const;
 
     // For LICM.
     virtual bool neverHoist() const { return false; }
 
     // Also for LICM. Test whether this definition is likely to be a call, which
     // would clobber all or many of the floating-point registers, such that
     // hoisting floating-point constants out of containing loops isn't likely to
     // be worthwhile.
--- a/js/src/jit/MIRGraph.cpp
+++ b/js/src/jit/MIRGraph.cpp
@@ -1198,19 +1198,31 @@ MIRGraph::dump(FILE *fp)
         fprintf(fp, "block%d:\n", iter->id());
         iter->dump(fp);
         fprintf(fp, "\n");
     }
 #endif
 }
 
 void
+MIRGraph::dump()
+{
+    dump(stderr);
+}
+
+void
 MBasicBlock::dump(FILE *fp)
 {
 #ifdef DEBUG
     for (MPhiIterator iter(phisBegin()); iter != phisEnd(); iter++) {
         iter->dump(fp);
     }
     for (MInstructionIterator iter(begin()); iter != end(); iter++) {
         iter->dump(fp);
     }
 #endif
 }
+
+void
+MBasicBlock::dump()
+{
+    dump(stderr);
+}
--- a/js/src/jit/MIRGraph.h
+++ b/js/src/jit/MIRGraph.h
@@ -469,16 +469,17 @@ class MBasicBlock : public TempObject, p
 
     bool strict() const {
         return info_.script()->strict;
     }
 
     void dumpStack(FILE *fp);
 
     void dump(FILE *fp);
+    void dump();
 
     // Track bailouts by storing the current pc in MIR instruction added at this
     // cycle. This is also used for tracking calls when profiling.
     void updateTrackedPc(jsbytecode *pc) {
         trackedPc_ = pc;
     }
 
     jsbytecode *trackedPc() {
@@ -678,16 +679,17 @@ class MIRGraph
 
     // The per-thread context. So as not to modify the calling convention for
     // parallel code, we obtain the current slice from thread-local storage.
     // This helper method will lazilly insert an MForkJoinSlice instruction in
     // the entry block and return the definition.
     MDefinition *forkJoinSlice();
 
     void dump(FILE *fp);
+    void dump();
 };
 
 class MDefinitionIterator
 {
 
   friend class MBasicBlock;
 
   private:
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -286,16 +286,25 @@ RangeAnalysis::removeBetaNodes()
 void
 SymbolicBound::print(Sprinter &sp) const
 {
     if (loop)
         sp.printf("[loop] ");
     sum.print(sp);
 }
 
+void
+SymbolicBound::dump() const
+{
+    Sprinter sp(GetIonContext()->cx);
+    sp.init();
+    print(sp);
+    fprintf(stderr, "%s\n", sp.string());
+}
+
 // Test whether the given range's exponent tells us anything that its lower
 // and upper bound values don't.
 static bool
 IsExponentInteresting(const Range *r)
 {
    // If it lacks either a lower or upper bound, the exponent is interesting.
    if (!r->hasInt32Bounds())
        return true;
@@ -360,16 +369,22 @@ void
 Range::dump(FILE *fp) const
 {
     Sprinter sp(GetIonContext()->cx);
     sp.init();
     print(sp);
     fprintf(fp, "%s\n", sp.string());
 }
 
+void
+Range::dump() const
+{
+    dump(stderr);
+}
+
 Range *
 Range::intersect(const Range *lhs, const Range *rhs, bool *emptyRange)
 {
     *emptyRange = false;
 
     if (!lhs && !rhs)
         return nullptr;
 
--- a/js/src/jit/RangeAnalysis.h
+++ b/js/src/jit/RangeAnalysis.h
@@ -58,16 +58,17 @@ struct SymbolicBound : public TempObject
     LinearSum sum;
 
     SymbolicBound(LoopIterationBound *loop, LinearSum sum)
       : loop(loop), sum(sum)
     {
     }
 
     void print(Sprinter &sp) const;
+    void dump() const;
 };
 
 class RangeAnalysis
 {
   protected:
     bool blockDominates(MBasicBlock *b, MBasicBlock *b2);
     void replaceDominatedUsesWith(MDefinition *orig, MDefinition *dom,
                                   MBasicBlock *block);
@@ -367,16 +368,17 @@ class Range : public TempObject {
 
         Range *r = new Range();
         r->setDouble(l, h);
         return r;
     }
 
     void print(Sprinter &sp) const;
     void dump(FILE *fp) const;
+    void dump() const;
     bool update(const Range *other);
 
     // Unlike the other operations, unionWith is an in-place
     // modification. This is to avoid a bunch of useless extra
     // copying when chaining together unions when handling Phi
     // nodes.
     void unionWith(const Range *other);
     static Range * intersect(const Range *lhs, const Range *rhs, bool *emptyRange);