Bug 1045948 - IonMonkey: Eliminate LDefintion::PASSTHROUGH. r=bhackett
authorDan Gohman <sunfish@mozilla.com>
Sat, 16 Aug 2014 13:13:13 -0700
changeset 200004 59aa0319941b936234c51af7a70e857689fb969e
parent 200003 14246833d2096dfa38e3f9083d06a7c55f59ad30
child 200005 8e45a9d7abfb29a06de7c09fbc24c9438c1a192b
push idunknown
push userunknown
push dateunknown
reviewersbhackett
bugs1045948
milestone34.0a1
Bug 1045948 - IonMonkey: Eliminate LDefintion::PASSTHROUGH. r=bhackett
js/src/jit/LIR.cpp
js/src/jit/LIR.h
js/src/jit/LiveRangeAllocator.cpp
js/src/jit/LiveRangeAllocator.h
js/src/jit/RegisterAllocator.cpp
js/src/jit/StupidAllocator.cpp
js/src/jit/arm/Lowering-arm.cpp
js/src/jit/mips/Lowering-mips.cpp
js/src/jit/shared/Lowering-shared-inl.h
js/src/jit/shared/Lowering-shared.h
js/src/jit/x86/Lowering-x86.cpp
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -366,18 +366,16 @@ PrintDefinition(char *buf, size_t size, 
         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());
-    else if (def.policy() == LDefinition::PASSTHROUGH)
-        cursor += JS_snprintf(cursor, end - cursor, ":-");
 }
 
 const char *
 LDefinition::toString() const
 {
     // Not reentrant!
     static char buf[40];
     PrintDefinition(buf, sizeof(buf), *this);
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -274,16 +274,17 @@ class LUse : public LAllocation
     }
 
     Policy policy() const {
         Policy policy = (Policy)((data() >> POLICY_SHIFT) & POLICY_MASK);
         return policy;
     }
     uint32_t virtualRegister() const {
         uint32_t index = (data() >> VREG_SHIFT) & VREG_MASK;
+        JS_ASSERT(index != 0);
         return index;
     }
     uint32_t registerCode() const {
         JS_ASSERT(policy() == FIXED);
         return (data() >> REG_SHIFT) & REG_MASK;
     }
     bool isFixedRegister() const {
         return policy() == FIXED;
@@ -406,23 +407,17 @@ class LDefinition
         //   * A register, which may not appear as any fixed temporary.
         //   * A stack slot or argument.
         //
         // Register allocation will not modify a fixed allocation.
         FIXED,
 
         // One definition per instruction must re-use the first input
         // allocation, which (for now) must be a register.
-        MUST_REUSE_INPUT,
-
-        // This definition's virtual register is the same as another; this is
-        // for instructions which consume a register and silently define it as
-        // the same register. It is not legal to use this if doing so would
-        // change the type of the virtual register.
-        PASSTHROUGH
+        MUST_REUSE_INPUT
     };
 
     enum Type {
         GENERAL,    // Generic, integer or pointer-width data (GPR).
         INT32,      // int32 data (GPR).
         OBJECT,     // Pointer that may be collected as garbage (GPR).
         SLOTS,      // Slots/elements pointer that may be moved by minor GCs (GPR).
         FLOAT32,    // 32-bit floating-point value (FPU).
@@ -503,17 +498,19 @@ class LDefinition
         return isFloatReg() == other.isFloatReg();
 #endif
     }
 
     bool isFloatReg() const {
         return type() == FLOAT32 || type() == DOUBLE || isSimdType();
     }
     uint32_t virtualRegister() const {
-        return (bits_ >> VREG_SHIFT) & VREG_MASK;
+        uint32_t index = (bits_ >> VREG_SHIFT) & VREG_MASK;
+        JS_ASSERT(index != 0);
+        return index;
     }
     LAllocation *output() {
         return &output_;
     }
     const LAllocation *output() const {
         return &output_;
     }
     bool isFixed() const {
--- a/js/src/jit/LiveRangeAllocator.cpp
+++ b/js/src/jit/LiveRangeAllocator.cpp
@@ -520,20 +520,20 @@ LiveRangeAllocator<VREG, forLSRA>::init(
     for (size_t i = 0; i < graph.numBlocks(); i++) {
         if (mir->shouldCancel("Create data structures (main loop)"))
             return false;
 
         LBlock *block = graph.getBlock(i);
         for (LInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
             for (size_t j = 0; j < ins->numDefs(); j++) {
                 LDefinition *def = ins->getDef(j);
-                if (def->policy() != LDefinition::PASSTHROUGH) {
-                    if (!vregs[def].init(alloc(), block, *ins, def, /* isTemp */ false))
-                        return false;
-                }
+                if (def->isBogusTemp())
+                    continue;
+                if (!vregs[def].init(alloc(), block, *ins, def, /* isTemp */ false))
+                    return false;
             }
 
             for (size_t j = 0; j < ins->numTemps(); j++) {
                 LDefinition *def = ins->getTemp(j);
                 if (def->isBogusTemp())
                     continue;
                 if (!vregs[def].init(alloc(), block, *ins, def, /* isTemp */ true))
                     return false;
@@ -660,60 +660,60 @@ LiveRangeAllocator<VREG, forLSRA>::build
                         }
                         if (!found && !addFixedRangeAtHead(*iter, outputOf(*ins), outputOf(*ins).next()))
                             return false;
                     }
                 }
             }
 
             for (size_t i = 0; i < ins->numDefs(); i++) {
-                if (ins->getDef(i)->policy() != LDefinition::PASSTHROUGH) {
-                    LDefinition *def = ins->getDef(i);
+                LDefinition *def = ins->getDef(i);
+                if (def->isBogusTemp())
+                    continue;
 
-                    CodePosition from;
-                    if (def->policy() == LDefinition::FIXED && def->output()->isRegister() && forLSRA) {
-                        // The fixed range covers the current instruction so the
-                        // interval for the virtual register starts at the next
-                        // instruction. If the next instruction has a fixed use,
-                        // this can lead to unnecessary register moves. To avoid
-                        // special handling for this, assert the next instruction
-                        // has no fixed uses. defineFixed guarantees this by inserting
-                        // an LNop.
-                        JS_ASSERT(!NextInstructionHasFixedUses(block, *ins));
-                        AnyRegister reg = def->output()->toRegister();
-                        if (!addFixedRangeAtHead(reg, inputOf(*ins), outputOf(*ins).next()))
-                            return false;
-                        from = outputOf(*ins).next();
-                    } else {
-                        from = forLSRA ? inputOf(*ins) : outputOf(*ins);
-                    }
+                CodePosition from;
+                if (def->policy() == LDefinition::FIXED && def->output()->isRegister() && forLSRA) {
+                    // The fixed range covers the current instruction so the
+                    // interval for the virtual register starts at the next
+                    // instruction. If the next instruction has a fixed use,
+                    // this can lead to unnecessary register moves. To avoid
+                    // special handling for this, assert the next instruction
+                    // has no fixed uses. defineFixed guarantees this by inserting
+                    // an LNop.
+                    JS_ASSERT(!NextInstructionHasFixedUses(block, *ins));
+                    AnyRegister reg = def->output()->toRegister();
+                    if (!addFixedRangeAtHead(reg, inputOf(*ins), outputOf(*ins).next()))
+                        return false;
+                    from = outputOf(*ins).next();
+                } else {
+                    from = forLSRA ? inputOf(*ins) : outputOf(*ins);
+                }
 
-                    if (def->policy() == LDefinition::MUST_REUSE_INPUT) {
-                        // MUST_REUSE_INPUT is implemented by allocating an output
-                        // register and moving the input to it. Register hints are
-                        // used to avoid unnecessary moves. We give the input an
-                        // LUse::ANY policy to avoid allocating a register for the
-                        // input.
-                        LUse *inputUse = ins->getOperand(def->getReusedInput())->toUse();
-                        JS_ASSERT(inputUse->policy() == LUse::REGISTER);
-                        JS_ASSERT(inputUse->usedAtStart());
-                        *inputUse = LUse(inputUse->virtualRegister(), LUse::ANY, /* usedAtStart = */ true);
-                    }
+                if (def->policy() == LDefinition::MUST_REUSE_INPUT) {
+                    // MUST_REUSE_INPUT is implemented by allocating an output
+                    // register and moving the input to it. Register hints are
+                    // used to avoid unnecessary moves. We give the input an
+                    // LUse::ANY policy to avoid allocating a register for the
+                    // input.
+                    LUse *inputUse = ins->getOperand(def->getReusedInput())->toUse();
+                    JS_ASSERT(inputUse->policy() == LUse::REGISTER);
+                    JS_ASSERT(inputUse->usedAtStart());
+                    *inputUse = LUse(inputUse->virtualRegister(), LUse::ANY, /* usedAtStart = */ true);
+                }
 
-                    LiveInterval *interval = vregs[def].getInterval(0);
-                    interval->setFrom(from);
+                LiveInterval *interval = vregs[def].getInterval(0);
+                interval->setFrom(from);
 
-                    // Ensure that if there aren't any uses, there's at least
-                    // some interval for the output to go into.
-                    if (interval->numRanges() == 0) {
-                        if (!interval->addRangeAtHead(from, from.next()))
-                            return false;
-                    }
-                    live->remove(def->virtualRegister());
+                // Ensure that if there aren't any uses, there's at least
+                // some interval for the output to go into.
+                if (interval->numRanges() == 0) {
+                    if (!interval->addRangeAtHead(from, from.next()))
+                        return false;
                 }
+                live->remove(def->virtualRegister());
             }
 
             for (size_t i = 0; i < ins->numTemps(); i++) {
                 LDefinition *temp = ins->getTemp(i);
                 if (temp->isBogusTemp())
                     continue;
 
                 if (forLSRA) {
--- a/js/src/jit/LiveRangeAllocator.h
+++ b/js/src/jit/LiveRangeAllocator.h
@@ -180,18 +180,16 @@ DefinitionCompatibleWith(LInstruction *i
             return false;
         return alloc.isFloatReg() == def->isFloatReg();
       case LDefinition::FIXED:
         return alloc == *def->output();
       case LDefinition::MUST_REUSE_INPUT:
         if (!alloc.isRegister() || !ins->numOperands())
             return false;
         return alloc == *ins->getOperand(def->getReusedInput());
-      case LDefinition::PASSTHROUGH:
-        return true;
       default:
         MOZ_ASSUME_UNREACHABLE("Unknown definition policy");
     }
 }
 
 #endif // DEBUG
 
 static inline LDefinition *
@@ -485,16 +483,17 @@ class VirtualRegister
     }
     void replaceInterval(LiveInterval *old, LiveInterval *interval) {
         JS_ASSERT(intervals_[old->index()] == old);
         interval->setIndex(old->index());
         intervals_[old->index()] = interval;
     }
     bool addInterval(LiveInterval *interval) {
         JS_ASSERT(interval->numRanges());
+        JS_ASSERT(interval->vreg() != 0);
 
         // Preserve ascending order for faster lookups.
         LiveInterval **found = nullptr;
         LiveInterval **i;
         for (i = intervals_.begin(); i != intervals_.end(); i++) {
             if (!found && interval->start() < (*i)->start())
                 found = i;
             if (found)
--- a/js/src/jit/RegisterAllocator.cpp
+++ b/js/src/jit/RegisterAllocator.cpp
@@ -48,24 +48,28 @@ AllocationIntegrityState::record()
             }
         }
 
         for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
             LInstruction *ins = *iter;
             InstructionInfo &info = instructions[ins->id()];
 
             for (size_t k = 0; k < ins->numTemps(); k++) {
-                uint32_t vreg = ins->getTemp(k)->virtualRegister();
-                virtualRegisters[vreg] = ins->getTemp(k);
+                if (!ins->getTemp(k)->isBogusTemp()) {
+                    uint32_t vreg = ins->getTemp(k)->virtualRegister();
+                    virtualRegisters[vreg] = ins->getTemp(k);
+                }
                 if (!info.temps.append(*ins->getTemp(k)))
                     return false;
             }
             for (size_t k = 0; k < ins->numDefs(); k++) {
-                uint32_t vreg = ins->getDef(k)->virtualRegister();
-                virtualRegisters[vreg] = ins->getDef(k);
+                if (!ins->getDef(k)->isBogusTemp()) {
+                    uint32_t vreg = ins->getDef(k)->virtualRegister();
+                    virtualRegisters[vreg] = ins->getDef(k);
+                }
                 if (!info.outputs.append(*ins->getDef(k)))
                     return false;
             }
             for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) {
                 if (!info.inputs.append(**alloc))
                     return false;
             }
         }
@@ -90,17 +94,17 @@ AllocationIntegrityState::check(bool pop
         for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
             LInstruction *ins = *iter;
 
             for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next())
                 JS_ASSERT(!alloc->isUse());
 
             for (size_t i = 0; i < ins->numDefs(); i++) {
                 LDefinition *def = ins->getDef(i);
-                JS_ASSERT_IF(def->policy() != LDefinition::PASSTHROUGH, !def->output()->isUse());
+                JS_ASSERT(!def->output()->isUse());
 
                 LDefinition oldDef = instructions[ins->id()].outputs[i];
                 JS_ASSERT_IF(oldDef.policy() == LDefinition::MUST_REUSE_INPUT,
                              *def->output() == *ins->getOperand(oldDef.getReusedInput()));
             }
 
             for (size_t i = 0; i < ins->numTemps(); i++) {
                 LDefinition *temp = ins->getTemp(i);
@@ -127,16 +131,18 @@ AllocationIntegrityState::check(bool pop
         LBlock *block = graph.getBlock(blockIndex);
         for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
             LInstruction *ins = *iter;
             const InstructionInfo &info = instructions[ins->id()];
 
             LSafepoint *safepoint = ins->safepoint();
             if (safepoint) {
                 for (size_t i = 0; i < ins->numTemps(); i++) {
+                    if (ins->getTemp(i)->isBogusTemp())
+                        continue;
                     uint32_t vreg = info.temps[i].virtualRegister();
                     LAllocation *alloc = ins->getTemp(i)->output();
                     if (!checkSafepointAllocation(ins, vreg, *alloc, populateSafepoints))
                         return false;
                 }
                 JS_ASSERT_IF(ins->isCall() && !populateSafepoints,
                              safepoint->liveRegs().empty(true) &&
                              safepoint->liveRegs().empty(false));
@@ -195,17 +201,17 @@ AllocationIntegrityState::checkIntegrity
         const InstructionInfo &info = instructions[ins->id()];
 
         // Make sure the physical location being tracked is not clobbered by
         // another instruction, and that if the originating vreg definition is
         // found that it is writing to the tracked location.
 
         for (size_t i = 0; i < ins->numDefs(); i++) {
             LDefinition *def = ins->getDef(i);
-            if (def->policy() == LDefinition::PASSTHROUGH)
+            if (def->isBogusTemp())
                 continue;
             if (info.outputs[i].virtualRegister() == vreg) {
                 JS_ASSERT(*def->output() == alloc);
 
                 // Found the original definition, done scanning.
                 return true;
             } else {
                 JS_ASSERT(*def->output() != alloc);
--- a/js/src/jit/StupidAllocator.cpp
+++ b/js/src/jit/StupidAllocator.cpp
@@ -46,18 +46,17 @@ StupidAllocator::init()
     if (!virtualRegisters.appendN((LDefinition *)nullptr, graph.numVirtualRegisters()))
         return false;
 
     for (size_t i = 0; i < graph.numBlocks(); i++) {
         LBlock *block = graph.getBlock(i);
         for (LInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
             for (size_t j = 0; j < ins->numDefs(); j++) {
                 LDefinition *def = ins->getDef(j);
-                if (def->policy() != LDefinition::PASSTHROUGH)
-                    virtualRegisters[def->virtualRegister()] = def;
+                virtualRegisters[def->virtualRegister()] = def;
             }
 
             for (size_t j = 0; j < ins->numTemps(); j++) {
                 LDefinition *def = ins->getTemp(j);
                 if (def->isBogusTemp())
                     continue;
                 virtualRegisters[def->virtualRegister()] = def;
             }
@@ -365,18 +364,17 @@ StupidAllocator::allocateForInstruction(
     // Find registers to hold all temporaries and outputs of the instruction.
     for (size_t i = 0; i < ins->numTemps(); i++) {
         LDefinition *def = ins->getTemp(i);
         if (!def->isBogusTemp())
             allocateForDefinition(ins, def);
     }
     for (size_t i = 0; i < ins->numDefs(); i++) {
         LDefinition *def = ins->getDef(i);
-        if (def->policy() != LDefinition::PASSTHROUGH)
-            allocateForDefinition(ins, def);
+        allocateForDefinition(ins, def);
     }
 
     // Allocate for remaining inputs which do not need to be in registers.
     for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) {
         if (!alloc->isUse())
             continue;
         LUse *use = alloc->toUse();
         uint32_t vreg = use->virtualRegister();
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -102,25 +102,24 @@ LIRGeneratorARM::visitBox(MBox *box)
     LBox *lir = new(alloc()) LBox(use(inner), inner->type());
 
     // Otherwise, we should not define a new register for the payload portion
     // of the output, so bypass defineBox().
     uint32_t vreg = getVirtualRegister();
     if (vreg >= MAX_VIRTUAL_REGISTERS)
         return false;
 
-    // Note that because we're using PASSTHROUGH, we do not change the type of
+    // Note that because we're using BogusTemp(), we do not change the type of
     // the definition. We also do not define the first output as "TYPE",
     // because it has no corresponding payload at (vreg + 1). Also note that
     // although we copy the input's original type for the payload half of the
-    // definition, this is only for clarity. PASSTHROUGH definitions are
+    // definition, this is only for clarity. BogusTemp() definitions are
     // ignored.
     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
-    lir->setDef(1, LDefinition(inner->virtualRegister(), LDefinition::TypeFrom(inner->type()),
-                               LDefinition::PASSTHROUGH));
+    lir->setDef(1, LDefinition::BogusTemp());
     box->setVirtualRegister(vreg);
     return add(lir);
 }
 
 bool
 LIRGeneratorARM::visitUnbox(MUnbox *unbox)
 {
     // An unbox on arm reads in a type tag (either in memory or a register) and
@@ -143,22 +142,21 @@ LIRGeneratorARM::visitUnbox(MUnbox *unbo
     // Swap the order we use the box pieces so we can re-use the payload register.
     LUnbox *lir = new(alloc()) LUnbox;
     lir->setOperand(0, usePayloadInRegisterAtStart(inner));
     lir->setOperand(1, useType(inner, LUse::REGISTER));
 
     if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
         return false;
 
-    // Note that PASSTHROUGH here is illegal, since types and payloads form two
-    // separate intervals. If the type becomes dead before the payload, it
-    // could be used as a Value without the type being recoverable. Unbox's
-    // purpose is to eagerly kill the definition of a type tag, so keeping both
-    // alive (for the purpose of gcmaps) is unappealing. Instead, we create a
-    // new virtual register.
+    // Types and payloads form two separate intervals. If the type becomes dead
+    // before the payload, it could be used as a Value without the type being
+    // recoverable. Unbox's purpose is to eagerly kill the definition of a type
+    // tag, so keeping both alive (for the purpose of gcmaps) is unappealing.
+    // Instead, we create a new virtual register.
     return defineReuseInput(lir, unbox, 0);
 }
 
 bool
 LIRGeneratorARM::visitReturn(MReturn *ret)
 {
     MDefinition *opd = ret->getOperand(0);
     JS_ASSERT(opd->type() == MIRType_Value);
--- a/js/src/jit/mips/Lowering-mips.cpp
+++ b/js/src/jit/mips/Lowering-mips.cpp
@@ -104,25 +104,24 @@ LIRGeneratorMIPS::visitBox(MBox *box)
     LBox *lir = new(alloc()) LBox(use(inner), inner->type());
 
     // Otherwise, we should not define a new register for the payload portion
     // of the output, so bypass defineBox().
     uint32_t vreg = getVirtualRegister();
     if (vreg >= MAX_VIRTUAL_REGISTERS)
         return false;
 
-    // Note that because we're using PASSTHROUGH, we do not change the type of
+    // Note that because we're using BogusTemp(), we do not change the type of
     // the definition. We also do not define the first output as "TYPE",
     // because it has no corresponding payload at (vreg + 1). Also note that
     // although we copy the input's original type for the payload half of the
-    // definition, this is only for clarity. PASSTHROUGH definitions are
+    // definition, this is only for clarity. BogusTemp() definitions are
     // ignored.
     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
-    lir->setDef(1, LDefinition(inner->virtualRegister(), LDefinition::TypeFrom(inner->type()),
-                               LDefinition::PASSTHROUGH));
+    lir->setDef(1, LDefinition::BogusTemp());
     box->setVirtualRegister(vreg);
     return add(lir);
 }
 
 bool
 LIRGeneratorMIPS::visitUnbox(MUnbox *unbox)
 {
     // An unbox on mips reads in a type tag (either in memory or a register) and
@@ -146,22 +145,21 @@ LIRGeneratorMIPS::visitUnbox(MUnbox *unb
     // register.
     LUnbox *lir = new(alloc()) LUnbox;
     lir->setOperand(0, usePayloadInRegisterAtStart(inner));
     lir->setOperand(1, useType(inner, LUse::REGISTER));
 
     if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
         return false;
 
-    // Note that PASSTHROUGH here is illegal, since types and payloads form two
-    // separate intervals. If the type becomes dead before the payload, it
-    // could be used as a Value without the type being recoverable. Unbox's
-    // purpose is to eagerly kill the definition of a type tag, so keeping both
-    // alive (for the purpose of gcmaps) is unappealing. Instead, we create a
-    // new virtual register.
+    // Types and payloads form two separate intervals. If the type becomes dead
+    // before the payload, it could be used as a Value without the type being
+    // recoverable. Unbox's purpose is to eagerly kill the definition of a type
+    // tag, so keeping both alive (for the purpose of gcmaps) is unappealing.
+    // Instead, we create a new virtual register.
     return defineReuseInput(lir, unbox, 0);
 }
 
 bool
 LIRGeneratorMIPS::visitReturn(MReturn *ret)
 {
     MDefinition *opd = ret->getOperand(0);
     MOZ_ASSERT(opd->type() == MIRType_Value);
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -221,40 +221,16 @@ LIRGeneratorShared::redefine(MDefinition
 
     if (!ensureDefined(as))
         return false;
     def->setVirtualRegister(as->virtualRegister());
     return true;
 }
 
 bool
-LIRGeneratorShared::defineAs(LInstruction *outLir, MDefinition *outMir, MDefinition *inMir)
-{
-    uint32_t vreg = inMir->virtualRegister();
-    LDefinition::Policy policy = LDefinition::PASSTHROUGH;
-
-    if (outMir->type() == MIRType_Value) {
-#ifdef JS_NUNBOX32
-        outLir->setDef(TYPE_INDEX,
-                       LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, policy));
-        outLir->setDef(PAYLOAD_INDEX,
-                       LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, policy));
-#elif JS_PUNBOX64
-        outLir->setDef(0, LDefinition(vreg, LDefinition::BOX, policy));
-#else
-# error "Unexpected boxing type"
-#endif
-    } else {
-        outLir->setDef(0, LDefinition(vreg, LDefinition::TypeFrom(inMir->type()), policy));
-    }
-    outLir->setMir(outMir);
-    return redefine(outMir, inMir);
-}
-
-bool
 LIRGeneratorShared::ensureDefined(MDefinition *mir)
 {
     if (mir->isEmittedAtUses()) {
         if (!mir->toInstruction()->accept(this))
             return false;
         JS_ASSERT(mir->isLowered());
     }
     return true;
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -148,20 +148,16 @@ class LIRGeneratorShared : public MDefin
 
     template <size_t Ops, size_t Temps>
     inline bool defineReuseInput(LInstructionHelper<1, Ops, Temps> *lir, MDefinition *mir, uint32_t operand);
 
     // Rather than defining a new virtual register, sets |ins| to have the same
     // virtual register as |as|.
     inline bool redefine(MDefinition *ins, MDefinition *as);
 
-    // Defines an IR's output as the same as another IR. This is similar to
-    // redefine(), but used when creating new LIR.
-    inline bool defineAs(LInstruction *outLir, MDefinition *outMir, MDefinition *inMir);
-
     TempAllocator &alloc() const {
         return graph.alloc();
     }
 
     uint32_t getVirtualRegister() {
         return lirGraph_.getVirtualRegister();
     }
 
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -95,25 +95,24 @@ LIRGeneratorX86::visitBox(MBox *box)
     LBox *lir = new(alloc()) LBox(use(inner), inner->type());
 
     // Otherwise, we should not define a new register for the payload portion
     // of the output, so bypass defineBox().
     uint32_t vreg = getVirtualRegister();
     if (vreg >= MAX_VIRTUAL_REGISTERS)
         return false;
 
-    // Note that because we're using PASSTHROUGH, we do not change the type of
+    // Note that because we're using BogusTemp(), we do not change the type of
     // the definition. We also do not define the first output as "TYPE",
     // because it has no corresponding payload at (vreg + 1). Also note that
     // although we copy the input's original type for the payload half of the
-    // definition, this is only for clarity. PASSTHROUGH definitions are
+    // definition, this is only for clarity. BogusTemp() definitions are
     // ignored.
     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
-    lir->setDef(1, LDefinition(inner->virtualRegister(), LDefinition::TypeFrom(inner->type()),
-                               LDefinition::PASSTHROUGH));
+    lir->setDef(1, LDefinition::BogusTemp());
     box->setVirtualRegister(vreg);
     return add(lir);
 }
 
 bool
 LIRGeneratorX86::visitUnbox(MUnbox *unbox)
 {
     // An unbox on x86 reads in a type tag (either in memory or a register) and
@@ -136,22 +135,21 @@ LIRGeneratorX86::visitUnbox(MUnbox *unbo
     // Swap the order we use the box pieces so we can re-use the payload register.
     LUnbox *lir = new(alloc()) LUnbox;
     lir->setOperand(0, usePayloadInRegisterAtStart(inner));
     lir->setOperand(1, useType(inner, LUse::ANY));
 
     if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
         return false;
 
-    // Note that PASSTHROUGH here is illegal, since types and payloads form two
-    // separate intervals. If the type becomes dead before the payload, it
-    // could be used as a Value without the type being recoverable. Unbox's
-    // purpose is to eagerly kill the definition of a type tag, so keeping both
-    // alive (for the purpose of gcmaps) is unappealing. Instead, we create a
-    // new virtual register.
+    // Types and payloads form two separate intervals. If the type becomes dead
+    // before the payload, it could be used as a Value without the type being
+    // recoverable. Unbox's purpose is to eagerly kill the definition of a type
+    // tag, so keeping both alive (for the purpose of gcmaps) is unappealing.
+    // Instead, we create a new virtual register.
     return defineReuseInput(lir, unbox, 0);
 }
 
 bool
 LIRGeneratorX86::visitReturn(MReturn *ret)
 {
     MDefinition *opd = ret->getOperand(0);
     JS_ASSERT(opd->type() == MIRType_Value);