Bug 1322093 part 6 - Add helpers for pushing/popping values. r=h4writer
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 21 Dec 2016 17:37:47 +0100
changeset 452481 cc3b8d218cc7e8515312919a291fac97cc59ff01
parent 452480 2cb264cab3a12716b995c17915706da6665dc2ca
child 452482 dec599fbdaed0b7bb59e17e122529d18212055ab
push id39415
push usermozilla@noorenberghe.ca
push dateWed, 21 Dec 2016 20:49:14 +0000
reviewersh4writer
bugs1322093
milestone53.0a1
Bug 1322093 part 6 - Add helpers for pushing/popping values. r=h4writer
js/src/jit/CacheIRCompiler.cpp
js/src/jit/CacheIRCompiler.h
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -19,29 +19,18 @@ CacheRegisterAllocator::useValueRegister
     OperandLocation& loc = operandLocations_[op.id()];
 
     switch (loc.kind()) {
       case OperandLocation::ValueReg:
         currentOpRegs_.add(loc.valueReg());
         return loc.valueReg();
 
       case OperandLocation::ValueStack: {
-        // The Value is on the stack. If it's on top of the stack, unbox and
-        // then pop it. If we need the registers later, we can always spill
-        // back. If it's not on the top of the stack, just unbox.
         ValueOperand reg = allocateValueRegister(masm);
-        if (loc.valueStack() == stackPushed_) {
-            masm.popValue(reg);
-            MOZ_ASSERT(stackPushed_ >= sizeof(js::Value));
-            stackPushed_ -= sizeof(js::Value);
-        } else {
-            MOZ_ASSERT(loc.valueStack() < stackPushed_);
-            masm.loadValue(Address(masm.getStackPointer(), stackPushed_ - loc.valueStack()), reg);
-        }
-        loc.setValueReg(reg);
+        popValue(masm, &loc, reg);
         return reg;
       }
 
       case OperandLocation::Constant: {
         ValueOperand reg = allocateValueRegister(masm);
         masm.moveValue(loc.constant(), reg);
         loc.setValueReg(reg);
         return reg;
@@ -75,28 +64,18 @@ CacheRegisterAllocator::useRegister(Macr
         availableRegs_.take(reg);
         masm.unboxObject(val, reg);
         loc.setPayloadReg(reg, typedId.type());
         currentOpRegs_.add(reg);
         return reg;
       }
 
       case OperandLocation::PayloadStack: {
-        // The payload is on the stack. If it's on top of the stack we can just
-        // pop it, else we emit a load.
         Register reg = allocateRegister(masm);
-        if (loc.payloadStack() == stackPushed_) {
-            masm.pop(reg);
-            MOZ_ASSERT(stackPushed_ >= sizeof(uintptr_t));
-            stackPushed_ -= sizeof(uintptr_t);
-        } else {
-            MOZ_ASSERT(loc.payloadStack() < stackPushed_);
-            masm.loadPtr(Address(masm.getStackPointer(), stackPushed_ - loc.payloadStack()), reg);
-        }
-        loc.setPayloadReg(reg, loc.payloadType());
+        popPayload(masm, &loc, reg);
         return reg;
       }
 
       case OperandLocation::ValueStack: {
         // The value is on the stack, but boxed. If it's on top of the stack we
         // unbox it and then remove it from the stack, else we just unbox.
         Register reg = allocateRegister(masm);
         if (loc.valueStack() == stackPushed_) {
@@ -209,30 +188,26 @@ CacheRegisterAllocator::allocateRegister
         // the stack.
         for (size_t i = 0; i < operandLocations_.length(); i++) {
             OperandLocation& loc = operandLocations_[i];
             if (loc.kind() == OperandLocation::PayloadReg) {
                 Register reg = loc.payloadReg();
                 if (currentOpRegs_.has(reg))
                     continue;
 
-                masm.push(reg);
-                stackPushed_ += sizeof(uintptr_t);
-                loc.setPayloadStack(stackPushed_, loc.payloadType());
+                spillOperand(masm, &loc);
                 availableRegs_.add(reg);
                 break; // We got a register, so break out of the loop.
             }
             if (loc.kind() == OperandLocation::ValueReg) {
                 ValueOperand reg = loc.valueReg();
                 if (currentOpRegs_.aliases(reg))
                     continue;
 
-                masm.pushValue(reg);
-                stackPushed_ += sizeof(js::Value);
-                loc.setValueStack(stackPushed_);
+                spillOperand(masm, &loc);
                 availableRegs_.add(reg);
                 break; // Break out of the loop.
             }
         }
     }
 
     // At this point, there must be a free register. (Ion ICs don't have as
     // many registers available, so once we support Ion code generation, we may
@@ -261,30 +236,28 @@ CacheRegisterAllocator::allocateFixedReg
 
     // The register must be used by some operand. Spill it to the stack.
     for (size_t i = 0; i < operandLocations_.length(); i++) {
         OperandLocation& loc = operandLocations_[i];
         if (loc.kind() == OperandLocation::PayloadReg) {
             if (loc.payloadReg() != reg)
                 continue;
 
-            masm.push(reg);
-            stackPushed_ += sizeof(uintptr_t);
-            loc.setPayloadStack(stackPushed_, loc.payloadType());
+            spillOperand(masm, &loc);
             currentOpRegs_.add(reg);
             return;
         }
         if (loc.kind() == OperandLocation::ValueReg) {
             if (!loc.valueReg().aliases(reg))
                 continue;
 
-            masm.pushValue(loc.valueReg());
-            stackPushed_ += sizeof(js::Value);
-            loc.setValueStack(stackPushed_);
-            availableRegs_.add(loc.valueReg());
+            ValueOperand valueReg = loc.valueReg();
+            spillOperand(masm, &loc);
+
+            availableRegs_.add(valueReg);
             availableRegs_.take(reg);
             currentOpRegs_.add(reg);
             return;
         }
     }
 
     MOZ_CRASH("Invalid register");
 }
@@ -335,55 +308,112 @@ CacheRegisterAllocator::knownType(ValOpe
       case OperandLocation::Uninitialized:
         break;
     }
 
     MOZ_CRASH("Invalid kind");
 }
 
 void
+CacheRegisterAllocator::spillOperand(MacroAssembler& masm, OperandLocation* loc)
+{
+    MOZ_ASSERT(loc >= operandLocations_.begin() && loc < operandLocations_.end());
+
+    if (loc->kind() == OperandLocation::ValueReg) {
+        stackPushed_ += sizeof(js::Value);
+        masm.pushValue(loc->valueReg());
+        loc->setValueStack(stackPushed_);
+        return;
+    }
+
+    MOZ_ASSERT(loc->kind() == OperandLocation::PayloadReg);
+
+    stackPushed_ += sizeof(uintptr_t);
+    masm.push(loc->payloadReg());
+    loc->setPayloadStack(stackPushed_, loc->payloadType());
+}
+
+void
+CacheRegisterAllocator::popPayload(MacroAssembler& masm, OperandLocation* loc, Register dest)
+{
+    MOZ_ASSERT(loc >= operandLocations_.begin() && loc < operandLocations_.end());
+    MOZ_ASSERT(stackPushed_ >= sizeof(uintptr_t));
+
+    // The payload is on the stack. If it's on top of the stack we can just
+    // pop it, else we emit a load.
+    if (loc->payloadStack() == stackPushed_) {
+        masm.pop(dest);
+        stackPushed_ -= sizeof(uintptr_t);
+    } else {
+        MOZ_ASSERT(loc->payloadStack() < stackPushed_);
+        masm.loadPtr(Address(masm.getStackPointer(), stackPushed_ - loc->payloadStack()), dest);
+    }
+
+    loc->setPayloadReg(dest, loc->payloadType());
+}
+
+void
+CacheRegisterAllocator::popValue(MacroAssembler& masm, OperandLocation* loc, ValueOperand dest)
+{
+    MOZ_ASSERT(loc >= operandLocations_.begin() && loc < operandLocations_.end());
+    MOZ_ASSERT(stackPushed_ >= sizeof(js::Value));
+
+    // The Value is on the stack. If it's on top of the stack we can just
+    // pop it, else we emit a load.
+    if (loc->valueStack() == stackPushed_) {
+        masm.popValue(dest);
+        stackPushed_ -= sizeof(js::Value);
+    } else {
+        MOZ_ASSERT(loc->valueStack() < stackPushed_);
+        masm.loadValue(Address(masm.getStackPointer(), stackPushed_ - loc->valueStack()), dest);
+    }
+
+    loc->setValueReg(dest);
+}
+
+bool
+OperandLocation::aliasesReg(const OperandLocation& other) const
+{
+    MOZ_ASSERT(&other != this);
+
+    switch (other.kind_) {
+      case PayloadReg:
+        return aliasesReg(other.payloadReg());
+      case ValueReg:
+        return aliasesReg(other.valueReg());
+      case PayloadStack:
+      case ValueStack:
+      case Constant:
+        return false;
+      case Uninitialized:
+        break;
+    }
+
+    MOZ_CRASH("Invalid kind");
+}
+
+void
 CacheRegisterAllocator::restoreInputState(MacroAssembler& masm)
 {
     size_t numInputOperands = origInputLocations_.length();
     MOZ_ASSERT(writer_.numInputOperands() == numInputOperands);
 
     for (size_t j = 0; j < numInputOperands; j++) {
         OperandLocation orig = origInputLocation(j);
         OperandLocation cur = operandLocation(j);
 
         MOZ_ASSERT(orig.kind() == OperandLocation::ValueReg);
 
         // We have a cycle if a destination register will be used later
         // as source register. If that happens, just push the current value
         // on the stack and later get it from there.
         for (size_t k = j + 1; k < numInputOperands; k++) {
-            OperandLocation laterSource = operandLocation(k);
-            switch (laterSource.kind()) {
-              case OperandLocation::ValueReg:
-                if (orig.aliasesReg(laterSource.valueReg())) {
-                    stackPushed_ += sizeof(js::Value);
-                    masm.pushValue(laterSource.valueReg());
-                    laterSource.setValueStack(stackPushed_);
-                }
-                continue;
-              case OperandLocation::PayloadReg:
-                if (orig.aliasesReg(laterSource.payloadReg())) {
-                    stackPushed_ += sizeof(uintptr_t);
-                    masm.push(laterSource.payloadReg());
-                    laterSource.setPayloadStack(stackPushed_, laterSource.payloadType());
-                }
-                continue;
-              case OperandLocation::PayloadStack:
-              case OperandLocation::ValueStack:
-              case OperandLocation::Constant:
-                continue;
-              case OperandLocation::Uninitialized:
-                break;
-            }
-            MOZ_CRASH("Invalid kind");
+            OperandLocation& laterSource = operandLocations_[k];
+            if (orig.aliasesReg(laterSource))
+                spillOperand(masm, &laterSource);
         }
 
         switch (cur.kind()) {
           case OperandLocation::ValueReg:
             masm.moveValue(cur.valueReg(), orig.valueReg());
             continue;
           case OperandLocation::PayloadReg:
             masm.tagValue(cur.payloadType(), cur.payloadReg(), orig.valueReg());
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -107,31 +107,33 @@ class OperandLocation
         kind_ = ValueStack;
         data_.valueStackPushed = stackPushed;
     }
     void setConstant(const Value& v) {
         kind_ = Constant;
         data_.constant = v;
     }
 
-    bool aliasesReg(Register reg) {
+    bool aliasesReg(Register reg) const {
         if (kind_ == PayloadReg)
             return payloadReg() == reg;
         if (kind_ == ValueReg)
             return valueReg().aliases(reg);
         return false;
     }
-    bool aliasesReg(ValueOperand reg) {
+    bool aliasesReg(ValueOperand reg) const {
 #if defined(JS_NUNBOX32)
         return aliasesReg(reg.typeReg()) || aliasesReg(reg.payloadReg());
 #else
         return aliasesReg(reg.valueReg());
 #endif
     }
 
+    bool aliasesReg(const OperandLocation& other) const;
+
     bool operator==(const OperandLocation& other) const;
     bool operator!=(const OperandLocation& other) const { return !operator==(other); }
 };
 
 // Class to track and allocate registers while emitting IC code.
 class MOZ_RAII CacheRegisterAllocator
 {
     // The original location of the inputs to the cache.
@@ -158,16 +160,21 @@ class MOZ_RAII CacheRegisterAllocator
 
     const CacheIRWriter& writer_;
 
     CacheRegisterAllocator(const CacheRegisterAllocator&) = delete;
     CacheRegisterAllocator& operator=(const CacheRegisterAllocator&) = delete;
 
     void freeDeadOperandRegisters();
 
+    void spillOperand(MacroAssembler& masm, OperandLocation* loc);
+
+    void popPayload(MacroAssembler& masm, OperandLocation* loc, Register dest);
+    void popValue(MacroAssembler& masm, OperandLocation* loc, ValueOperand dest);
+
   public:
     friend class AutoScratchRegister;
     friend class AutoScratchRegisterExcluding;
 
     explicit CacheRegisterAllocator(const CacheIRWriter& writer)
       : allocatableRegs_(GeneralRegisterSet::All()),
         stackPushed_(0),
         currentInstruction_(0),