[INFER] Allow ValueRemat to contain FP registers, don't break doubles in setelem_dense and Array.push, bug 657220.
authorBrian Hackett <bhackett1024@gmail.com>
Sun, 15 May 2011 08:17:36 -0700
changeset 75052 55438ad5632e85be9f3c27023b9a8053c90a9d9f
parent 75051 ef1ce31f66b9054c6c4a81ce7e0e49b705ef6ebe
child 75053 a7b22d3523be8abec2f11a860846e633122961d3
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs657220
milestone6.0a1
[INFER] Allow ValueRemat to contain FP registers, don't break doubles in setelem_dense and Array.push, bug 657220.
js/src/methodjit/FastBuiltins.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/FrameState.cpp
js/src/methodjit/FrameState.h
js/src/methodjit/ICLabels.h
js/src/methodjit/NunboxAssembler.h
js/src/methodjit/PunboxAssembler.h
js/src/methodjit/RematInfo.h
--- a/js/src/methodjit/FastBuiltins.cpp
+++ b/js/src/methodjit/FastBuiltins.cpp
@@ -318,17 +318,17 @@ mjit::Compiler::compileArrayPush(FrameEn
     /* This behaves like an assignment this[this.length] = arg; */
 
     /* Filter out silly cases. */
     if (frame.haveSameBacking(thisValue, arg) || thisValue->isConstant())
         return Compile_InlineAbort;
 
     /* Allocate registers. */
     ValueRemat vr;
-    frame.pinEntry(arg, vr);
+    frame.pinEntry(arg, vr, /* breakDouble = */ false);
 
     RegisterID objReg = frame.tempRegForData(thisValue);
     frame.pinReg(objReg);
 
     RegisterID slotsReg = frame.allocReg();
 
     RegisterID lengthReg = frame.allocReg();
     masm.load32(Address(objReg, offsetof(JSObject, privateData)), lengthReg);
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1072,17 +1072,17 @@ mjit::Compiler::jsop_setelem_dense()
     if (!id->isTypeKnown()) {
         Jump guard = frame.testInt32(Assembler::NotEqual, id);
         stubcc.linkExit(guard, Uses(3));
     }
 
     // Allocate registers.
 
     ValueRemat vr;
-    frame.pinEntry(value, vr);
+    frame.pinEntry(value, vr, /* breakDouble = */ false);
 
     Int32Key key = id->isConstant()
                  ? Int32Key::FromConstant(id->getValue().toInt32())
                  : Int32Key::FromRegister(frame.tempRegForData(id));
     bool pinKey = !key.isConstant() && !frame.haveSameBacking(id, value);
     if (pinKey)
         frame.pinReg(key.reg());
 
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -2325,24 +2325,28 @@ FrameState::forgetKnownDouble(FrameEntry
     regstate(typeReg).associate(fe, RematInfo::TYPE);
     regstate(dataReg).associate(fe, RematInfo::DATA);
     fe->type.setRegister(typeReg);
     fe->data.setRegister(dataReg);
     freeReg(fpreg);
 }
 
 void
-FrameState::pinEntry(FrameEntry *fe, ValueRemat &vr)
+FrameState::pinEntry(FrameEntry *fe, ValueRemat &vr, bool breakDouble)
 {
+    if (breakDouble && !fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE))
+        forgetKnownDouble(fe);
+
     if (fe->isConstant()) {
         vr = ValueRemat::FromConstant(fe->getValue());
+    } else if (fe->isType(JSVAL_TYPE_DOUBLE)) {
+        FPRegisterID fpreg = tempFPRegForData(fe);
+        pinReg(fpreg);
+        vr = ValueRemat::FromFPRegister(fpreg);
     } else {
-        if (fe->isType(JSVAL_TYPE_DOUBLE))
-            forgetKnownDouble(fe);
-
         // Pin the type register so it can't spill.
         MaybeRegisterID maybePinnedType = maybePinType(fe);
 
         // Get and pin the data register.
         RegisterID dataReg = tempRegForData(fe);
         pinReg(dataReg);
 
         if (fe->isTypeKnown()) {
@@ -2359,31 +2363,33 @@ FrameState::pinEntry(FrameEntry *fe, Val
     // Set these bits last, since allocation could have caused a sync.
     vr.isDataSynced = fe->data.synced();
     vr.isTypeSynced = fe->type.synced();
 }
 
 void
 FrameState::unpinEntry(const ValueRemat &vr)
 {
-    if (!vr.isConstant()) {
+    if (vr.isFPRegister()) {
+        unpinReg(vr.fpReg());
+    } else if (!vr.isConstant()) {
         if (!vr.isTypeKnown())
             unpinReg(vr.typeReg());
         unpinReg(vr.dataReg());
     }
 }
 
 void
 FrameState::ensureValueSynced(Assembler &masm, FrameEntry *fe, const ValueRemat &vr)
 {
 #if defined JS_PUNBOX64
     if (!vr.isDataSynced || !vr.isTypeSynced)
         masm.storeValue(vr, addressOf(fe));
 #elif defined JS_NUNBOX32
-    if (vr.isConstant()) {
+    if (vr.isConstant() || vr.isFPRegister()) {
         if (!vr.isDataSynced || !vr.isTypeSynced)
             masm.storeValue(vr.value(), addressOf(fe));
     } else {
         if (!vr.isDataSynced)
             masm.storePayload(vr.dataReg(), addressOf(fe));
         if (!vr.isTypeSynced) {
             if (vr.isTypeKnown())
                 masm.storeTypeTag(ImmType(vr.knownType()), addressOf(fe));
--- a/js/src/methodjit/FrameState.h
+++ b/js/src/methodjit/FrameState.h
@@ -486,20 +486,21 @@ class FrameState
      * frame entry's data payload.
      * Since the register is not bound to a FrameEntry,
      * it MUST be explicitly freed with freeReg().
      */
     RegisterID copyInt32ConstantIntoReg(FrameEntry *fe);
     RegisterID copyInt32ConstantIntoReg(Assembler &masm, FrameEntry *fe);
 
     /*
-     * Gets registers for the components of fe where needed,
-     * pins them and stores into vr.
+     * Gets registers for the components of fe where needed, pins them and
+     * stores into vr. If breakDouble is set, vr is guaranteed not to be a
+     * floating point register.
      */
-    void pinEntry(FrameEntry *fe, ValueRemat &vr);
+    void pinEntry(FrameEntry *fe, ValueRemat &vr, bool breakDouble = true);
 
     /* Unpins registers from a call to pinEntry. */
     void unpinEntry(const ValueRemat &vr);
 
     /* Syncs fe to memory, given its state as constructed by a call to pinEntry. */
     void ensureValueSynced(Assembler &masm, FrameEntry *fe, const ValueRemat &vr);
 
     struct BinaryAlloc {
--- a/js/src/methodjit/ICLabels.h
+++ b/js/src/methodjit/ICLabels.h
@@ -254,16 +254,17 @@ struct SetPropLabels : MacroAssemblerTyp
     }
 
     CodeLocationDataLabel32 getInlineShapeData(CodeLocationLabel fastPathStart, int shapeGuardOffset) {
         return fastPathStart.dataLabel32AtOffset(shapeGuardOffset + getInlineShapeDataOffset());
     }
 
     void setDslotsLoad(MacroAssembler &masm, Label fastPathRejoin, Label beforeLoad,
                        const ValueRemat &rhs) {
+        JS_ASSERT(!rhs.isFPRegister());
         int offset = masm.differenceBetween(fastPathRejoin, beforeLoad);
         setDslotsLoadOffset(offset, rhs.isConstant(), rhs.isTypeKnown());
     }
 
     CodeLocationInstruction getDslotsLoad(CodeLocationLabel fastPathRejoin, const ValueRemat &vr) {
         return fastPathRejoin.instructionAtOffset(getDslotsLoadOffset(vr));
     }
 
--- a/js/src/methodjit/NunboxAssembler.h
+++ b/js/src/methodjit/NunboxAssembler.h
@@ -272,16 +272,17 @@ class NunboxAssembler : public JSC::Macr
         return start;
 #elif defined JS_CPU_ARM || defined JS_CPU_SPARC
         return store64WithAddressOffsetPatch(type, payload, address);
 #endif
     }
 
     /* Overloaded for store with value remat info. */
     DataLabel32 storeValueWithAddressOffsetPatch(const ValueRemat &vr, Address address) {
+        JS_ASSERT(!vr.isFPRegister());
         if (vr.isConstant()) {
             return storeValueWithAddressOffsetPatch(vr.value(), address);
         } else if (vr.isTypeKnown()) {
             ImmType type(vr.knownType());
             RegisterID data(vr.dataReg());
             return storeValueWithAddressOffsetPatch(type, data, address);
         } else {
             RegisterID type(vr.typeReg());
@@ -315,16 +316,20 @@ class NunboxAssembler : public JSC::Macr
         storeTypeTag(type, address);
         storePayload(payload, address);
     }
 
     template <typename T>
     Label storeValue(const ValueRemat &vr, T address) {
         if (vr.isConstant()) {
             return storeValue(vr.value(), address);
+        } else if (vr.isFPRegister()) {
+            Label l = label();
+            storeDouble(vr.fpReg(), address);
+            return l;
         } else {
             if (vr.isTypeKnown())
                 storeTypeTag(ImmType(vr.knownType()), address);
             else
                 storeTypeTag(vr.typeReg(), address);
             Label l = label();
             storePayload(vr.dataReg(), address);
             return l;
--- a/js/src/methodjit/PunboxAssembler.h
+++ b/js/src/methodjit/PunboxAssembler.h
@@ -184,16 +184,17 @@ class PunboxAssembler : public JSC::Macr
         jv.asBits = JSVAL_BITS(Jsvalify(v));
 
         move(ImmPtr(reinterpret_cast<void*>(jv.asBits)), Registers::ValueReg);
         return storePtrWithAddressOffsetPatch(Registers::ValueReg, valueOf(address));
     }
 
     /* Overloaded for store with value remat info. */
     DataLabel32 storeValueWithAddressOffsetPatch(const ValueRemat &vr, Address address) {
+        JS_ASSERT(!vr.isFPRegister());
         if (vr.isConstant()) {
             return storeValueWithAddressOffsetPatch(vr.value(), address);
         } else if (vr.isTypeKnown()) {
             ImmType type(vr.knownType());
             RegisterID data(vr.dataReg());
             return storeValueWithAddressOffsetPatch(type, data, address);
         } else {
             RegisterID type(vr.typeReg());
@@ -255,16 +256,18 @@ class PunboxAssembler : public JSC::Macr
 
         storePtr(Imm64(jv.asBits), valueOf(address));
     }
 
     template <typename T>
     void storeValue(const ValueRemat &vr, T address) {
         if (vr.isConstant())
             storeValue(vr.value(), address);
+        else if (vr.isFPRegister())
+            storeDouble(vr.fpReg(), address);
         else if (vr.isTypeKnown())
             storeValueFromComponents(ImmType(vr.knownType()), vr.dataReg(), address);
         else
             storeValueFromComponents(vr.typeReg(), vr.dataReg(), address);
     }
 
     template <typename T>
     Jump guardNotHole(T address) {
--- a/js/src/methodjit/RematInfo.h
+++ b/js/src/methodjit/RematInfo.h
@@ -109,72 +109,90 @@ struct StateRemat {
         JS_ASSERT(inRegister());
         return reg_;
     }
 };
 
 /* Lightweight version of FrameEntry. */
 struct ValueRemat {
     typedef JSC::MacroAssembler::RegisterID RegisterID;
+    typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
     union {
         struct {
             union {
                 int32       typeRemat_;
                 JSValueType knownType_;
             } type;
             int32   dataRemat_   : MIN_STATE_REMAT_BITS;
             bool    isTypeKnown_ : 1;
         } s;
         jsval v_;
+        FPRegisterID fpreg_;
     } u;
     bool isConstant_    : 1;
+    bool isFPRegister_  : 1;
     bool isDataSynced   : 1;
     bool isTypeSynced   : 1;
 
     static ValueRemat FromConstant(const Value &v) {
         ValueRemat vr;
         vr.isConstant_ = true;
+        vr.isFPRegister_ = false;
         vr.u.v_ = Jsvalify(v);
         return vr;
     }
+    static ValueRemat FromFPRegister(FPRegisterID fpreg) {
+        ValueRemat vr;
+        vr.isConstant_ = false;
+        vr.isFPRegister_ = true;
+        vr.u.fpreg_ = fpreg;
+        return vr;
+    }
     static ValueRemat FromKnownType(JSValueType type, RegisterID dataReg) {
         ValueRemat vr;
         vr.isConstant_ = false;
+        vr.isFPRegister_ = false;
         vr.u.s.type.knownType_ = type;
         vr.u.s.isTypeKnown_ = true;
         vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32();
 
         // Assert bitfields are okay.
         JS_ASSERT(vr.dataReg() == dataReg);
         return vr;
     }
     static ValueRemat FromRegisters(RegisterID typeReg, RegisterID dataReg) {
         ValueRemat vr;
         vr.isConstant_ = false;
+        vr.isFPRegister_ = false;
         vr.u.s.isTypeKnown_ = false;
         vr.u.s.type.typeRemat_ = StateRemat::FromRegister(typeReg).toInt32();
         vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32();
 
         // Assert bitfields are okay.
         JS_ASSERT(vr.dataReg() == dataReg);
         JS_ASSERT(vr.typeReg() == typeReg);
         return vr;
     }
 
+    FPRegisterID fpReg() const {
+        JS_ASSERT(isFPRegister());
+        return u.fpreg_;
+    }
     RegisterID dataReg() const {
-        JS_ASSERT(!isConstant());
+        JS_ASSERT(!isConstant() && !isFPRegister());
         return dataRemat().reg();
     }
     RegisterID typeReg() const {
         JS_ASSERT(!isTypeKnown());
         return typeRemat().reg();
     }
 
     bool isConstant() const { return isConstant_; }
-    bool isTypeKnown() const { return isConstant() || u.s.isTypeKnown_; }
+    bool isFPRegister() const { return isFPRegister_; }
+    bool isTypeKnown() const { return isConstant() || isFPRegister() || u.s.isTypeKnown_; }
 
     StateRemat dataRemat() const {
         JS_ASSERT(!isConstant());
         return StateRemat::FromInt32(u.s.dataRemat_);
     }
     StateRemat typeRemat() const {
         JS_ASSERT(!isTypeKnown());
         return StateRemat::FromInt32(u.s.type.typeRemat_);
@@ -186,16 +204,18 @@ struct ValueRemat {
     JSValueType knownType() const {
         JS_ASSERT(isTypeKnown());
         if (isConstant()) {
             const Value v = value();
             if (v.isDouble())
                 return JSVAL_TYPE_DOUBLE;
             return v.extractNonDoubleType();
         }
+        if (isFPRegister())
+            return JSVAL_TYPE_DOUBLE;
         return u.s.type.knownType_;
     }
     bool isType(JSValueType type_) const {
         return isTypeKnown() && knownType() == type_;
     }
 };
 
 /*