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 172214 4b627d104594af5c0edfa43343cdf745b93574e2
parent 172213 f2ed1e244513e952c6a800874577263c9d6b51a0
child 172215 c81e58d7c31d625c858c488c29b60791e63964bc
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs943449
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);