Bug 1045948 - IonMonkey: Make bogus LAllocations have an all-zeros bit pattern. r=bhackett
authorDan Gohman <sunfish@mozilla.com>
Sat, 16 Aug 2014 13:13:14 -0700
changeset 200005 8e45a9d7abfb29a06de7c09fbc24c9438c1a192b
parent 200004 59aa0319941b936234c51af7a70e857689fb969e
child 200006 cafba2a1b359a8205906cad600b363be4d7e4f6d
push idunknown
push userunknown
push dateunknown
reviewersbhackett
bugs1045948
milestone34.0a1
Bug 1045948 - IonMonkey: Make bogus LAllocations have an all-zeros bit pattern. r=bhackett
js/src/jit/BacktrackingAllocator.h
js/src/jit/LIR.cpp
js/src/jit/LIR.h
js/src/jit/LinearScan.cpp
js/src/jit/LiveRangeAllocator.cpp
js/src/jit/LiveRangeAllocator.h
js/src/jit/Lowering.cpp
js/src/jit/RegisterAllocator.cpp
js/src/jit/shared/Lowering-shared.cpp
--- a/js/src/jit/BacktrackingAllocator.h
+++ b/js/src/jit/BacktrackingAllocator.h
@@ -77,17 +77,17 @@ class BacktrackingVirtualRegister : publ
         return mustCopyInput_;
     }
 
     void setCanonicalSpill(LAllocation alloc) {
         JS_ASSERT(!alloc.isUse());
         canonicalSpill_ = alloc;
     }
     const LAllocation *canonicalSpill() const {
-        return canonicalSpill_.isUse() ? nullptr : &canonicalSpill_;
+        return canonicalSpill_.isBogus() ? nullptr : &canonicalSpill_;
     }
 
     void setCanonicalSpillExclude(CodePosition pos) {
         canonicalSpillExclude_ = pos;
     }
     bool hasCanonicalSpillExclude() const {
         return canonicalSpillExclude_.bits() != 0;
     }
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -357,32 +357,34 @@ static const char * const TypeChars[] =
 };
 
 static void
 PrintDefinition(char *buf, size_t size, const LDefinition &def)
 {
     char *cursor = buf;
     char *end = buf + size;
 
-    if (def.virtualRegister())
-        cursor += JS_snprintf(cursor, end - cursor, "v%u", def.virtualRegister());
-
+    cursor += JS_snprintf(cursor, end - cursor, "v%u", def.virtualRegister());
     cursor += JS_snprintf(cursor, end - cursor, "<%s>", TypeChars[def.type()]);
 
     if (def.policy() == LDefinition::FIXED)
         cursor += JS_snprintf(cursor, end - cursor, ":%s", def.output()->toString());
     else if (def.policy() == LDefinition::MUST_REUSE_INPUT)
         cursor += JS_snprintf(cursor, end - cursor, ":tied(%u)", def.getReusedInput());
 }
 
 const char *
 LDefinition::toString() const
 {
     // Not reentrant!
     static char buf[40];
+
+    if (isBogusTemp())
+        return "bogus";
+
     PrintDefinition(buf, sizeof(buf), *this);
     return buf;
 }
 
 static void
 PrintUse(char *buf, size_t size, const LUse *use)
 {
     switch (use->policy()) {
@@ -411,16 +413,19 @@ PrintUse(char *buf, size_t size, const L
 }
 
 const char *
 LAllocation::toString() const
 {
     // Not reentrant!
     static char buf[40];
 
+    if (isBogus())
+        return "bogus";
+
     switch (kind()) {
       case LAllocation::CONSTANT_VALUE:
       case LAllocation::CONSTANT_INDEX:
         return "c";
       case LAllocation::GPR:
         JS_snprintf(buf, sizeof(buf), "%s", toGeneralReg()->reg().name());
         return buf;
       case LAllocation::FPU:
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -66,19 +66,19 @@ class LAllocation : public TempObject
 
   protected:
     static const uintptr_t DATA_BITS = (sizeof(uint32_t) * 8) - KIND_BITS;
     static const uintptr_t DATA_SHIFT = KIND_SHIFT + KIND_BITS;
     static const uintptr_t DATA_MASK = (1 << DATA_BITS) - 1;
 
   public:
     enum Kind {
-        USE,            // Use of a virtual register, with physical allocation policy.
         CONSTANT_VALUE, // Constant js::Value.
         CONSTANT_INDEX, // Constant arbitrary index.
+        USE,            // Use of a virtual register, with physical allocation policy.
         GPR,            // General purpose register.
         FPU,            // Floating-point register.
         STACK_SLOT,     // Stack slot.
         ARGUMENT_SLOT   // Argument slot.
     };
 
   protected:
     int32_t data() const {
@@ -98,38 +98,44 @@ class LAllocation : public TempObject
         setKindAndData(kind, data);
     }
     explicit LAllocation(Kind kind) {
         setKindAndData(kind, 0);
     }
 
   public:
     LAllocation() : bits_(0)
-    { }
+    {
+        JS_ASSERT(isBogus());
+    }
 
     static LAllocation *New(TempAllocator &alloc) {
         return new(alloc) LAllocation();
     }
     template <typename T>
     static LAllocation *New(TempAllocator &alloc, const T &other) {
         return new(alloc) LAllocation(other);
     }
 
     // The value pointer must be rooted in MIR and have its low bits cleared.
     explicit LAllocation(const Value *vp) {
+        JS_ASSERT(vp);
         bits_ = uintptr_t(vp);
         JS_ASSERT((bits_ & (KIND_MASK << KIND_SHIFT)) == 0);
         bits_ |= CONSTANT_VALUE << KIND_SHIFT;
     }
     inline explicit LAllocation(AnyRegister reg);
 
     Kind kind() const {
         return (Kind)((bits_ >> KIND_SHIFT) & KIND_MASK);
     }
 
+    bool isBogus() const {
+        return bits_ == 0;
+    }
     bool isUse() const {
         return kind() == USE;
     }
     bool isConstant() const {
         return isConstantValue() || isConstantIndex();
     }
     bool isConstantValue() const {
         return kind() == CONSTANT_VALUE;
@@ -323,21 +329,16 @@ class LFloatReg : public LAllocation
 // Arbitrary constant index.
 class LConstantIndex : public LAllocation
 {
     explicit LConstantIndex(uint32_t index)
       : LAllocation(CONSTANT_INDEX, index)
     { }
 
   public:
-    // Used as a placeholder for inputs that can be ignored.
-    static LConstantIndex Bogus() {
-        return LConstantIndex(0);
-    }
-
     static LConstantIndex FromIndex(uint32_t index) {
         return LConstantIndex(index);
     }
 
     uint32_t index() const {
         return data();
     }
 };
@@ -394,27 +395,27 @@ class LDefinition
     static const uint32_t VREG_SHIFT = POLICY_SHIFT + POLICY_BITS;
     static const uint32_t VREG_MASK = (1 << VREG_BITS) - 1;
 
   public:
     // Note that definitions, by default, are always allocated a register,
     // unless the policy specifies that an input can be re-used and that input
     // is a stack slot.
     enum Policy {
-        // A random register of an appropriate class will be assigned.
-        REGISTER,
-
         // The policy is predetermined by the LAllocation attached to this
         // definition. The allocation may be:
         //   * A register, which may not appear as any fixed temporary.
         //   * A stack slot or argument.
         //
         // Register allocation will not modify a fixed allocation.
         FIXED,
 
+        // A random register of an appropriate class will be assigned.
+        REGISTER,
+
         // One definition per instruction must re-use the first input
         // allocation, which (for now) must be a register.
         MUST_REUSE_INPUT
     };
 
     enum Type {
         GENERAL,    // Generic, integer or pointer-width data (GPR).
         INT32,      // int32 data (GPR).
@@ -457,20 +458,22 @@ class LDefinition
 
     LDefinition(uint32_t index, Type type, const LAllocation &a)
       : output_(a)
     {
         set(index, type, FIXED);
     }
 
     LDefinition() : bits_(0)
-    { }
+    {
+        JS_ASSERT(isBogusTemp());
+    }
 
     static LDefinition BogusTemp() {
-        return LDefinition(GENERAL, LConstantIndex::Bogus());
+        return LDefinition();
     }
 
     Policy policy() const {
         return (Policy)((bits_ >> POLICY_SHIFT) & POLICY_MASK);
     }
     Type type() const {
         return (Type)((bits_ >> TYPE_SHIFT) & TYPE_MASK);
     }
@@ -512,17 +515,17 @@ class LDefinition
     }
     const LAllocation *output() const {
         return &output_;
     }
     bool isFixed() const {
         return policy() == FIXED;
     }
     bool isBogusTemp() const {
-        return isFixed() && output()->isConstantIndex();
+        return isFixed() && output()->isBogus();
     }
     void setVirtualRegister(uint32_t index) {
         JS_ASSERT(index < VREG_MASK);
         bits_ &= ~(VREG_MASK << VREG_SHIFT);
         bits_ |= index << VREG_SHIFT;
     }
     void setOutput(const LAllocation &a) {
         output_ = a;
--- a/js/src/jit/LinearScan.cpp
+++ b/js/src/jit/LinearScan.cpp
@@ -79,17 +79,17 @@ LinearScanAllocator::allocateRegisters()
     for (size_t i = 0; i < AnyRegister::Total; i++) {
         if (fixedIntervals[i]->numRanges() > 0)
             fixed.pushBack(fixedIntervals[i]);
     }
 
     // Iterate through all intervals in ascending start order.
     CodePosition prevPosition = CodePosition::MIN;
     while ((current = unhandled.dequeue()) != nullptr) {
-        JS_ASSERT(current->getAllocation()->isUse());
+        JS_ASSERT(current->getAllocation()->isBogus());
         JS_ASSERT(current->numRanges() > 0);
 
         if (mir->shouldCancel("LSRA Allocate Registers (main loop)"))
             return false;
 
         CodePosition position = current->start();
         const Requirement *req = current->requirement();
         const Requirement *hint = current->hint();
--- a/js/src/jit/LiveRangeAllocator.cpp
+++ b/js/src/jit/LiveRangeAllocator.cpp
@@ -1075,17 +1075,17 @@ LiveInterval::toString() const
             cursor += n;
         }
 
         n = JS_snprintf(cursor, end - cursor, ")");
         if (n < 0) return "???";
         cursor += n;
     }
 
-    if (alloc_.kind() != LAllocation::USE) {
+    if (!alloc_.isBogus()) {
         n = JS_snprintf(cursor, end - cursor, " has(%s)", alloc_.toString());
         if (n < 0) return "???";
         cursor += n;
     }
 
     n = JS_snprintf(cursor, end - cursor, "%s", rangesToString());
     if (n < 0) return "???";
     cursor += n;
--- a/js/src/jit/LiveRangeAllocator.h
+++ b/js/src/jit/LiveRangeAllocator.h
@@ -47,41 +47,41 @@ class Requirement
         // These have dedicated constructors.
         JS_ASSERT(kind != FIXED && kind != MUST_REUSE_INPUT);
     }
 
     explicit Requirement(LAllocation fixed)
       : kind_(FIXED),
         allocation_(fixed)
     {
-        JS_ASSERT(fixed == LAllocation() || !fixed.isUse());
+        JS_ASSERT(!fixed.isBogus() && !fixed.isUse());
     }
 
     // Only useful as a hint, encodes where the fixed requirement is used to
     // avoid allocating a fixed register too early.
     Requirement(LAllocation fixed, CodePosition at)
       : kind_(FIXED),
         allocation_(fixed),
         position_(at)
     {
-        JS_ASSERT(fixed == LAllocation() || !fixed.isUse());
+        JS_ASSERT(!fixed.isBogus() && !fixed.isUse());
     }
 
     Requirement(uint32_t vreg, CodePosition at)
       : kind_(MUST_REUSE_INPUT),
         allocation_(LUse(vreg, LUse::ANY)),
         position_(at)
     { }
 
     Kind kind() const {
         return kind_;
     }
 
     LAllocation allocation() const {
-        JS_ASSERT(!allocation_.isUse());
+        JS_ASSERT(!allocation_.isBogus() && !allocation_.isUse());
         return allocation_;
     }
 
     uint32_t virtualRegister() const {
         JS_ASSERT(allocation_.isUse());
         JS_ASSERT(kind() == MUST_REUSE_INPUT);
         return allocation_.toUse()->virtualRegister();
     }
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2576,18 +2576,16 @@ LIRGenerator::visitInArray(MInArray *ins
     JS_ASSERT(ins->index()->type() == MIRType_Int32);
     JS_ASSERT(ins->initLength()->type() == MIRType_Int32);
     JS_ASSERT(ins->object()->type() == MIRType_Object);
     JS_ASSERT(ins->type() == MIRType_Boolean);
 
     LAllocation object;
     if (ins->needsNegativeIntCheck())
         object = useRegister(ins->object());
-    else
-        object = LConstantIndex::Bogus();
 
     LInArray *lir = new(alloc()) LInArray(useRegister(ins->elements()),
                                           useRegisterOrConstant(ins->index()),
                                           useRegister(ins->initLength()),
                                           object);
     return define(lir, ins) && assignSafepoint(lir, ins);
 }
 
--- a/js/src/jit/RegisterAllocator.cpp
+++ b/js/src/jit/RegisterAllocator.cpp
@@ -570,17 +570,19 @@ RegisterAllocator::dumpInstructions()
                 fprintf(stderr, " [def %s]", ins->getDef(i)->toString());
 
             for (size_t i = 0; i < ins->numTemps(); i++) {
                 LDefinition *temp = ins->getTemp(i);
                 if (!temp->isBogusTemp())
                     fprintf(stderr, " [temp %s]", temp->toString());
             }
 
-            for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next())
-                fprintf(stderr, " [use %s]", alloc->toString());
+            for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) {
+                if (!alloc->isBogus())
+                    fprintf(stderr, " [use %s]", alloc->toString());
+            }
 
             fprintf(stderr, "\n");
         }
     }
     fprintf(stderr, "\n");
 #endif // DEBUG
 }
--- a/js/src/jit/shared/Lowering-shared.cpp
+++ b/js/src/jit/shared/Lowering-shared.cpp
@@ -131,20 +131,20 @@ LIRGeneratorShared::buildSnapshot(LInstr
         MOZ_ASSERT_IF(!ins->isConstant(), !ins->isEmittedAtUses());
 
         // The register allocation will fill these fields in with actual
         // register/stack assignments. During code generation, we can restore
         // interpreter state with the given information. Note that for
         // constants, including known types, we record a dummy placeholder,
         // since we can recover the same information, much cleaner, from MIR.
         if (ins->isConstant() || ins->isUnused()) {
-            *type = LConstantIndex::Bogus();
-            *payload = LConstantIndex::Bogus();
+            *type = LAllocation();
+            *payload = LAllocation();
         } else if (ins->type() != MIRType_Value) {
-            *type = LConstantIndex::Bogus();
+            *type = LAllocation();
             *payload = use(ins, LUse(LUse::KEEPALIVE));
         } else {
             *type = useType(ins, LUse::KEEPALIVE);
             *payload = usePayload(ins, LUse::KEEPALIVE);
         }
     }
 
     return snapshot;
@@ -182,17 +182,17 @@ LIRGeneratorShared::buildSnapshot(LInstr
         // Snapshot operands other than constants should never be
         // emitted-at-uses. Try-catch support depends on there being no
         // code between an instruction and the LOsiPoint that follows it.
         MOZ_ASSERT_IF(!def->isConstant(), !def->isEmittedAtUses());
 
         LAllocation *a = snapshot->getEntry(index++);
 
         if (def->isUnused()) {
-            *a = LConstantIndex::Bogus();
+            *a = LAllocation();
             continue;
         }
 
         *a = useKeepaliveOrConstant(def);
     }
 
     return snapshot;
 }