Bug 588021: Port SETPROP PIC for ARM. (r=dmandelin)
authorChris Leary <cdleary@mozilla.com>
Thu, 13 Jan 2011 22:41:42 -0800
changeset 60595 151a8a6ce36bb7793b70729f32cc001cb92d5a43
parent 60594 cbdee93fd16348e9f5c0b35689555ca57c003bbd
child 60596 d3ca3ea64e570e0bd7c1d230e996b0857b431a99
push idunknown
push userunknown
push dateunknown
reviewersdmandelin
bugs588021
milestone2.0b10pre
Bug 588021: Port SETPROP PIC for ARM. (r=dmandelin)
js/src/configure.in
js/src/methodjit/BaseCompiler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/ICLabels.h
js/src/methodjit/NunboxAssembler.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/PolyIC.h
js/src/methodjit/PunboxAssembler.h
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2909,40 +2909,43 @@ dnl Configure JIT support
 case "$target" in
 i?86-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=i386
     ENABLE_METHODJIT=1
     ENABLE_MONOIC=1
     ENABLE_POLYIC=1
     ENABLE_POLYIC_GETPROP=1
+    ENABLE_POLYIC_SETPROP=1
     ENABLE_POLYIC_BIND=1
     ENABLE_POLYIC_NAME=1
     AC_DEFINE(JS_CPU_X86)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 x86_64*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=X64
     ENABLE_METHODJIT=1
     ENABLE_MONOIC=1
     ENABLE_POLYIC=1
     ENABLE_POLYIC_GETPROP=1
+    ENABLE_POLYIC_SETPROP=1
     ENABLE_POLYIC_BIND=1
     ENABLE_POLYIC_NAME=1
     AC_DEFINE(JS_CPU_X64)
     AC_DEFINE(JS_PUNBOX64)
     ;;
 arm*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=ARM
     ENABLE_METHODJIT=1
     ENABLE_MONOIC=1
     ENABLE_POLYIC=1
     ENABLE_POLYIC_GETPROP=1
+    ENABLE_POLYIC_SETPROP=1
     ENABLE_POLYIC_BIND=1
     ENABLE_POLYIC_NAME=1
     AC_DEFINE(JS_CPU_ARM)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 sparc*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=Sparc
--- a/js/src/methodjit/BaseCompiler.h
+++ b/js/src/methodjit/BaseCompiler.h
@@ -43,16 +43,22 @@
 #include "jscntxt.h"
 #include "jstl.h"
 #include "assembler/assembler/MacroAssembler.h"
 #include "assembler/assembler/LinkBuffer.h"
 #include "assembler/assembler/RepatchBuffer.h"
 #include "assembler/jit/ExecutableAllocator.h"
 #include <limits.h>
 
+#if defined JS_CPU_ARM
+# define POST_INST_OFFSET(__expr) ((__expr) - sizeof(ARMWord))
+#else
+# define POST_INST_OFFSET(__expr) (__expr)
+#endif
+
 namespace js {
 namespace mjit {
 
 struct MacroAssemblerTypedefs {
     typedef JSC::MacroAssembler::Label Label;
     typedef JSC::MacroAssembler::Imm32 Imm32;
     typedef JSC::MacroAssembler::ImmPtr ImmPtr;
     typedef JSC::MacroAssembler::RegisterID RegisterID;
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -3367,16 +3367,19 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
     JSOp op = JSOp(*PC);
 
     ic::PICInfo::Kind kind = (op == JSOP_SETMETHOD)
                              ? ic::PICInfo::SETMETHOD
                              : ic::PICInfo::SET;
     PICGenInfo pic(kind, op, usePropCache);
     pic.atom = atom;
 
+    RESERVE_IC_SPACE(masm);
+    RESERVE_OOL_SPACE(stubcc.masm);
+
     /* Guard that the type is an object. */
     Jump typeCheck;
     if (!lhs->isTypeKnown()) {
         RegisterID reg = frame.tempRegForType(lhs);
         pic.typeReg = reg;
 
         /* Start the hot path where it's easy to patch it. */
         pic.fastPathStart = masm.label();
@@ -3410,47 +3413,39 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
     RegisterID shapeReg = frame.allocReg();
     pic.shapeReg = shapeReg;
 
     frame.unpinEntry(vr);
 
     /* Guard on shape. */
     masm.loadShape(objReg, shapeReg);
     pic.shapeGuard = masm.label();
-    DataLabel32 inlineShapeOffsetLabel;
+    DataLabel32 inlineShapeData;
     Jump j = masm.branch32WithPatch(Assembler::NotEqual, shapeReg,
                                     Imm32(int32(JSObjectMap::INVALID_SHAPE)),
-                                    inlineShapeOffsetLabel);
-    DBGLABEL(dbgInlineShapeJump);
+                                    inlineShapeData);
+    Label afterInlineShapeJump = masm.label();
 
     /* Slow path. */
     {
         pic.slowPathStart = stubcc.linkExit(j, Uses(2));
 
         stubcc.leave();
         passICAddress(&pic);
         pic.slowPathCall = OOL_STUBCALL(ic::SetProp);
+        CHECK_OOL_SPACE();
     }
 
     /* Load dslots. */
-#if defined JS_NUNBOX32
-    DBGLABEL(dbgDslots);
-#elif defined JS_PUNBOX64
-    Label dslotsLoadLabel = masm.label();
-#endif
-    masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
+    Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)),
+                                                       objReg);
 
     /* Store RHS into object slot. */
     Address slot(objReg, 1 << 24);
-#if defined JS_NUNBOX32
-    Label dbgInlineStoreType = masm.storeValue(vr, slot);
-#elif defined JS_PUNBOX64
-    masm.storeValue(vr, slot);
-#endif
-    DBGLABEL(dbgAfterValueStore);
+    Label inlineValueStore = masm.storeValueWithAddressOffsetPatch(vr, slot);
     pic.fastPathRejoin = masm.label();
 
     frame.freeReg(objReg);
     frame.freeReg(shapeReg);
 
     /* "Pop under", taking out object (LHS) and leaving RHS. */
     frame.shimmy(1);
 
@@ -3459,44 +3454,31 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
         if (pic.hasTypeCheck)
             typeCheck.linkTo(stubcc.masm.label(), &stubcc.masm);
         stubcc.rejoin(Changes(1));
     }
 
     RETURN_IF_OOM(false);
 
     SetPropLabels &labels = pic.setPropLabels();
-    labels.setInlineShapeOffset(masm.differenceBetween(pic.shapeGuard, inlineShapeOffsetLabel));
-#if defined JS_PUNBOX64
-    labels.setDslotsLoadOffset(masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel));
-    JS_ASSERT(masm.differenceBetween(inlineShapeOffsetLabel, dbgInlineShapeJump) == SETPROP_INLINE_SHAPE_JUMP);
-    JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgAfterValueStore) == SETPROP_INLINE_STORE_VALUE);
-#elif defined JS_NUNBOX32
-    JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineShapeJump) == SETPROP_INLINE_SHAPE_JUMP);
-    if (vr.isConstant()) {
-        /* Constants are offset inside the opcode by 4. */
-        JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgInlineStoreType)-4 == SETPROP_INLINE_STORE_CONST_TYPE);
-        JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgAfterValueStore)-4 == SETPROP_INLINE_STORE_CONST_DATA);
-        JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgDslots) == SETPROP_DSLOTS_BEFORE_CONSTANT);
-    } else if (vr.isTypeKnown()) {
-        JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgInlineStoreType)-4 == SETPROP_INLINE_STORE_KTYPE_TYPE);
-        JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgAfterValueStore) == SETPROP_INLINE_STORE_KTYPE_DATA);
-        JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgDslots) == SETPROP_DSLOTS_BEFORE_KTYPE);
-    } else {
-        JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgInlineStoreType) == SETPROP_INLINE_STORE_DYN_TYPE);
-        JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgAfterValueStore) == SETPROP_INLINE_STORE_DYN_DATA);
-        JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgDslots) == SETPROP_DSLOTS_BEFORE_DYNAMIC);
-    }
+    labels.setInlineShapeData(masm, pic.shapeGuard, inlineShapeData);
+    labels.setDslotsLoad(masm, pic.fastPathRejoin, dslotsLoadLabel, vr);
+    labels.setInlineValueStore(masm, pic.fastPathRejoin, inlineValueStore, vr);
+#ifdef JS_CPU_X64
+    labels.setInlineShapeJump(masm, inlineShapeData, afterInlineShapeJump);
+#else
+    labels.setInlineShapeJump(masm, pic.shapeGuard, afterInlineShapeJump);
 #endif
 
     pics.append(pic);
     return true;
 }
 #endif
 
+
 #ifdef JS_POLYIC_NAME
 void
 mjit::Compiler::jsop_name(JSAtom *atom)
 {
     PICGenInfo pic(ic::PICInfo::NAME, JSOp(*PC), true);
 
     RESERVE_IC_SPACE(masm);
 
--- a/js/src/methodjit/ICLabels.h
+++ b/js/src/methodjit/ICLabels.h
@@ -38,26 +38,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #if !defined jsjaeger_ic_labels_h__ && defined JS_METHODJIT
 #define jsjaeger_ic_labels_h__
 
-#include "jscntxt.h"
-#include "jstl.h"
-#include "jsvector.h"
-#include "assembler/assembler/MacroAssembler.h"
-#include "assembler/assembler/CodeLocation.h"
-#include "methodjit/CodeGenIncludes.h"
-#include "methodjit/MethodJIT.h"
-#include "BaseAssembler.h"
-#include "RematInfo.h"
-#include "BaseCompiler.h"
+#include "methodjit/BaseCompiler.h"
 
 class ICOffsetInitializer {
   public:
     ICOffsetInitializer();
 };
 
 namespace js {
 namespace mjit {
@@ -129,22 +120,22 @@ struct GetPropLabels : MacroAssemblerTyp
     }
 
     void setInlineTypeJump(MacroAssembler &masm, Label fastPathStart, Label afterTypeJump) {
         int offset = masm.differenceBetween(fastPathStart, afterTypeJump);
         setInlineTypeJumpOffset(offset);
     }
 
     CodeLocationJump getInlineTypeJump(CodeLocationLabel fastPathStart) {
-#if defined JS_CPU_X86 || defined JS_CPU_X64
         return fastPathStart.jumpAtOffset(getInlineTypeJumpOffset());
-#elif defined JS_CPU_ARM
-        /* Type check is after the testObject, so offset by one instruction to get the jump. */
-        return fastPathStart.jumpAtOffset(getInlineTypeJumpOffset() - sizeof(ARMWord));
-#endif
+    }
+
+    void setStubShapeJump(MacroAssembler &masm, Label stubStart, Label shapeJump) {
+        int offset = masm.differenceBetween(stubStart, shapeJump);
+        setStubShapeJumpOffset(offset);
     }
 
     /* Offset-based interface */
 
     void setDslotsLoadOffset(int offset) {
 #ifdef JS_HAS_IC_LABELS
         dslotsLoadOffset = offset;
 #endif
@@ -153,42 +144,40 @@ struct GetPropLabels : MacroAssemblerTyp
 
     void setInlineShapeOffset(int offset) {
 #ifdef JS_HAS_IC_LABELS
         inlineShapeOffset = offset;
 #endif
         JS_ASSERT(offset == inlineShapeOffset);
     }
     
-    void setStubShapeJump(int offset) {
+    void setStubShapeJumpOffset(int offset) {
 #ifdef JS_HAS_IC_LABELS
         stubShapeJumpOffset = offset;
 #endif
         JS_ASSERT(offset == stubShapeJumpOffset);
     }
 
     int getInlineShapeJumpOffset() {
-#if defined JS_CPU_X86
-        return INLINE_SHAPE_JUMP;
-#elif defined JS_CPU_X64
+#if defined JS_CPU_X64
         return getInlineShapeOffset() + INLINE_SHAPE_JUMP;
-#elif defined JS_CPU_ARM
-        return INLINE_SHAPE_JUMP - sizeof(ARMWord);
+#else
+        return POST_INST_OFFSET(INLINE_SHAPE_JUMP);
 #endif
     }
 
     void setInlineShapeJumpOffset(int offset) {
         JS_ASSERT(INLINE_SHAPE_JUMP == offset);
     }
 
     int getInlineTypeJumpOffset() {
 #if defined JS_CPU_X86 || defined JS_CPU_X64
         return INLINE_TYPE_JUMP;
 #elif defined JS_CPU_ARM
-        return inlineTypeJumpOffset;
+        return POST_INST_OFFSET(inlineTypeJumpOffset);
 #endif
     }
 
     void setInlineTypeJumpOffset(int offset) {
 #if defined JS_CPU_X86 || defined JS_CPU_X64
         JS_ASSERT(INLINE_TYPE_JUMP == offset);
 #elif defined JS_CPU_ARM
         inlineTypeJumpOffset = offset;
@@ -198,21 +187,17 @@ struct GetPropLabels : MacroAssemblerTyp
 
     int getInlineShapeOffset() {
         return inlineShapeOffset;
     }
     int getDslotsLoadOffset() {
         return dslotsLoadOffset;
     }
     int getStubShapeJumpOffset() {
-#if defined JS_CPU_X86 || defined JS_CPU_X64
-        return stubShapeJumpOffset;
-#elif defined JS_CPU_ARM
-        return stubShapeJumpOffset - sizeof(ARMWord);
-#endif
+        return POST_INST_OFFSET(stubShapeJumpOffset);
     }
 
   private:
     /* Offset from storeBack to beginning of 'mov dslots, addr' */
     int32 dslotsLoadOffset : 8;
 
     /* Offset from shapeGuard to end of shape comparison. */
     int32 inlineShapeOffset : 8;
@@ -238,73 +223,192 @@ struct GetPropLabels : MacroAssemblerTyp
     static const int32 INLINE_SHAPE_JUMP = 12;
 
     /* Offset from the fast path to the type guard jump. */
     int32 inlineTypeJumpOffset : 8;
 #endif
 };
 
 /* SetPropCompiler */
-struct SetPropLabels {
+struct SetPropLabels : MacroAssemblerTypedefs {
     friend class ::ICOffsetInitializer;
 
-#ifdef JS_PUNBOX64
-    void setDslotsLoadOffset(int offset) {
-# ifdef JS_HAS_IC_LABELS
-        dslotsLoadOffset = offset;
-# endif
-        JS_ASSERT(offset == dslotsLoadOffset);
+    void setInlineValueStore(MacroAssembler &masm, Label fastPathRejoin, Label inlineValueStore,
+                             const ValueRemat &vr) {
+        int offset = masm.differenceBetween(fastPathRejoin, inlineValueStore);
+        setInlineValueStoreOffset(offset, vr.isConstant(), vr.isTypeKnown());
+    }
+
+    CodeLocationLabel getInlineValueStore(CodeLocationLabel fastPathRejoin, const ValueRemat &vr) {
+        return fastPathRejoin.labelAtOffset(getInlineValueStoreOffset(vr.isConstant(),
+                                                                      vr.isTypeKnown()));
+    }
+
+    void setInlineShapeData(MacroAssembler &masm, Label shapeGuard, DataLabel32 inlineShapeData) {
+        int offset = masm.differenceBetween(shapeGuard, inlineShapeData);
+        setInlineShapeDataOffset(offset);
+    }
+
+    CodeLocationDataLabel32 getInlineShapeData(CodeLocationLabel fastPathStart, int shapeGuardOffset) {
+        return fastPathStart.dataLabel32AtOffset(shapeGuardOffset + getInlineShapeDataOffset());
+    }
+
+    CodeLocationJump getInlineShapeJump(CodeLocationLabel fastPathStart, int shapeGuardOffset) {
+        return fastPathStart.jumpAtOffset(shapeGuardOffset + getInlineShapeJumpOffset());
+    }
+
+    void setDslotsLoad(MacroAssembler &masm, Label fastPathRejoin, Label beforeLoad,
+                       const ValueRemat &rhs) {
+        int offset = masm.differenceBetween(fastPathRejoin, beforeLoad);
+        setDslotsLoadOffset(offset, rhs.isConstant(), rhs.isTypeKnown());
     }
-#endif
+
+    CodeLocationInstruction getDslotsLoad(CodeLocationLabel fastPathRejoin, const ValueRemat &vr) {
+        return fastPathRejoin.instructionAtOffset(getDslotsLoadOffset(vr));
+    }
+
+    /*
+     * Note: on x64, the base is the inlineShapeLabel DataLabel32, whereas on other
+     * platforms the base is the shapeGuard.
+     */
+    template <typename T>
+    void setInlineShapeJump(MacroAssembler &masm, T base, Label afterJump) {
+        setInlineShapeJumpOffset(masm.differenceBetween(base, afterJump));
+    }
 
-    int getDslotsLoadOffset() {
-#ifdef JS_PUNBOX64
-        return dslotsLoadOffset;
+    void setStubShapeJump(MacroAssembler &masm, Label stubStart, Label afterShapeJump) {
+        int offset = masm.differenceBetween(stubStart, afterShapeJump);
+        setStubShapeJumpOffset(offset);
+    }
+
+    /* Offset-based interface. */
+
+    void setDslotsLoadOffset(int offset, bool isConstant, bool isTypeKnown) {
+#if defined JS_HAS_IC_LABELS
+        dslotsLoadOffset = offset;
+        JS_ASSERT(offset == dslotsLoadOffset);
+#elif defined JS_CPU_X86
+        JS_ASSERT_IF(isConstant, offset == INLINE_DSLOTS_BEFORE_CONSTANT);
+        JS_ASSERT_IF(isTypeKnown && !isConstant, offset == INLINE_DSLOTS_BEFORE_KTYPE);
+        JS_ASSERT_IF(!isTypeKnown, offset == INLINE_DSLOTS_BEFORE_DYNAMIC);
 #else
-        JS_NOT_REACHED("this is inlined");
-        return 0;
+# error
 #endif
     }
 
-    void setInlineShapeOffset(int offset) {
+    int getDslotsLoadOffset(const ValueRemat &vr) {
+#if defined JS_CPU_X86
+        if (vr.isConstant())
+            return INLINE_DSLOTS_BEFORE_CONSTANT;
+        if (vr.isTypeKnown())
+            return INLINE_DSLOTS_BEFORE_KTYPE;
+        return INLINE_DSLOTS_BEFORE_DYNAMIC;
+#else
+        (void) vr;
+        return dslotsLoadOffset;
+#endif
+    }
+
+    void setInlineShapeDataOffset(int offset) {
 #ifdef JS_HAS_IC_LABELS
-        inlineShapeOffset = offset;
+        inlineShapeDataOffset = offset;
 #endif
-        JS_ASSERT(offset == inlineShapeOffset);
+        JS_ASSERT(offset == inlineShapeDataOffset);
+    }
+
+    void setStubShapeJumpOffset(int offset) {
+#ifdef JS_HAS_IC_LABELS
+        stubShapeJumpOffset = offset;
+#endif
+        JS_ASSERT(offset == stubShapeJumpOffset);
     }
 
-    void setStubShapeJump(int offset) {
+    void setInlineValueStoreOffset(int offset, bool isConstant, bool isTypeKnown) {
 #ifdef JS_HAS_IC_LABELS
-        stubShapeJump = offset;
+        inlineValueStoreOffset = offset;
+        JS_ASSERT(offset == inlineValueStoreOffset);
+#elif defined JS_CPU_X86
+        JS_ASSERT_IF(isConstant, offset == INLINE_VALUE_STORE_CONSTANT);
+        JS_ASSERT_IF(isTypeKnown && !isConstant, offset == INLINE_VALUE_STORE_KTYPE);
+        JS_ASSERT_IF(!isTypeKnown && !isConstant, offset == INLINE_VALUE_STORE_DYNAMIC);
 #endif
-        JS_ASSERT(offset == stubShapeJump);
+    }
+
+    void setInlineShapeJumpOffset(int offset) {
+#ifdef JS_HAS_IC_LABELS
+        inlineShapeJumpOffset = offset;
+#endif
+        JS_ASSERT(offset == inlineShapeJumpOffset);
     }
 
-    int getInlineShapeOffset() {
-        return inlineShapeOffset;
+    int getInlineShapeJumpOffset() {
+        return POST_INST_OFFSET(inlineShapeDataOffset + INLINE_SHAPE_JUMP);
+    }
+
+    int getInlineShapeDataOffset() {
+        return inlineShapeDataOffset;
+    }
+
+    int getStubShapeJumpOffset() {
+        return POST_INST_OFFSET(stubShapeJumpOffset);
     }
-    int getStubShapeJump() {
-        return stubShapeJump;
+
+    int getInlineValueStoreOffset(bool isConstant, bool isTypeKnown) {
+#ifdef JS_HAS_IC_LABELS
+        return inlineValueStoreOffset;
+#elif defined JS_CPU_X86
+        if (isConstant)
+            return INLINE_VALUE_STORE_CONSTANT;
+        else if (isTypeKnown)
+            return INLINE_VALUE_STORE_KTYPE;
+        else
+            return INLINE_VALUE_STORE_DYNAMIC;
+#endif
     }
 
   private:
-#ifdef JS_PUNBOX64
     /* Offset from storeBack to beginning of 'mov dslots, addr'. */
+#if defined JS_CPU_X86
+    static const int INLINE_DSLOTS_BEFORE_CONSTANT = -23;
+    static const int INLINE_DSLOTS_BEFORE_KTYPE = -19;
+    static const int INLINE_DSLOTS_BEFORE_DYNAMIC = -15;
+#else
     int32 dslotsLoadOffset : 8;
 #endif
 
     /* Offset from shapeGuard to end of shape comparison. */
-    int32 inlineShapeOffset : 8;
+    int32 inlineShapeDataOffset : 8;
 
     /* 
      * Offset from lastStubStart to end of shape jump.
      * TODO: We can redefine the location of lastStubStart to be
      * after the jump -- at which point this is always 0.
      */
-    int32 stubShapeJump : 8;
+    int32 stubShapeJumpOffset : 8;
+
+#if defined JS_CPU_X86
+    static const int INLINE_VALUE_STORE_CONSTANT = -20;
+    static const int INLINE_VALUE_STORE_KTYPE = -16;
+    static const int INLINE_VALUE_STORE_DYNAMIC = -12;
+#else
+    int32 inlineValueStoreOffset : 8;
+#endif
+
+    /* Offset from shapeGuard to the end of the shape jump. */
+    int32 inlineShapeJumpOffset : 8;
+
+#if defined JS_CPU_X86
+    static const int INLINE_SHAPE_JUMP = 0;
+#elif defined JS_CPU_X64
+    static const int INLINE_SHAPE_JUMP = 6;
+#elif defined JS_CPU_ARM
+    static const int INLINE_SHAPE_JUMP = 12;
+#else
+# error
+#endif
 };
 
 /* BindNameCompiler */
 struct BindNameLabels : MacroAssemblerTypedefs {
     friend class ::ICOffsetInitializer;
 
     void setInlineJumpOffset(int offset) {
 #ifdef JS_HAS_IC_LABELS
@@ -406,9 +510,8 @@ struct ScopeNameLabels : MacroAssemblerT
     int32 stubJumpOffset : 8;
 };
 
 } /* namespace ic */
 } /* namespace mjit */
 } /* namespace js */
 
 #endif /* jsjaeger_ic_labels_h__ */
-
--- a/js/src/methodjit/NunboxAssembler.h
+++ b/js/src/methodjit/NunboxAssembler.h
@@ -262,16 +262,31 @@ class NunboxAssembler : public JSC::Macr
 #elif defined JS_CPU_ARM
         DataLabel32 store = store64WithAddressOffsetPatch(type, payload, address);
         JS_ASSERT(differenceBetween(start, store) == 0);
         (void) store;
         return start;
 #endif
     }
 
+    /* Overloaded for store with value remat info. */
+    Label storeValueWithAddressOffsetPatch(const ValueRemat &vr, Address address) {
+        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());
+            RegisterID data(vr.dataReg());
+            return storeValueWithAddressOffsetPatch(type, data, address);
+        }
+    }
+
     /*
      * Stores type first, then payload.
      */
     template <typename T>
     Label storeValue(const Value &v, T address) {
         jsval_layout jv;
         jv.asBits = JSVAL_BITS(Jsvalify(v));
 
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -78,18 +78,22 @@ ICOffsetInitializer::ICOffsetInitializer
         labels.dslotsLoadOffset = -15;
         labels.inlineShapeOffset = 6;
         labels.stubShapeJumpOffset = 12;
         labels.inlineValueLoadOffset = -12;
 #endif
     }
     {
         SetPropLabels &labels = PICInfo::setPropLabels_;
-        labels.inlineShapeOffset = 6;
-        labels.stubShapeJump = 12;
+#if defined JS_CPU_X86
+        labels.inlineShapeDataOffset = 6;
+        /* Store w/ address offset patch is two movs. */
+        labels.inlineShapeJumpOffset = 12;
+        labels.stubShapeJumpOffset = 12;
+#endif
     }
     {
         BindNameLabels &labels = PICInfo::bindNameLabels_;
 #if defined JS_CPU_X86
         labels.inlineJumpOffset = 10;
         labels.stubJumpOffset = 5;
 #endif
     }
@@ -183,104 +187,47 @@ class PICStubCompiler : public BaseCompi
 
 #if defined JS_POLYIC_SETPROP
 class SetPropCompiler : public PICStubCompiler
 {
     JSObject *obj;
     JSAtom *atom;
     int lastStubSecondShapeGuard;
 
-    static int32 dslotsLoadOffset(ic::PICInfo &pic) {
-#if defined JS_NUNBOX32
-        if (pic.u.vr.isConstant())
-            return SETPROP_DSLOTS_BEFORE_CONSTANT;
-        if (pic.u.vr.isTypeKnown())
-            return SETPROP_DSLOTS_BEFORE_KTYPE;
-        return SETPROP_DSLOTS_BEFORE_DYNAMIC;
-#elif defined JS_PUNBOX64
-        return pic.setPropLabels().getDslotsLoadOffset();
-#endif
-    }
-
-#if defined JS_NUNBOX32
-    inline int32 inlineTypeOffset() {
-        if (pic.u.vr.isConstant())
-            return SETPROP_INLINE_STORE_CONST_TYPE;
-        if (pic.u.vr.isTypeKnown())
-            return SETPROP_INLINE_STORE_KTYPE_TYPE;
-        return SETPROP_INLINE_STORE_DYN_TYPE;
-    }
-#endif
-
-#if defined JS_NUNBOX32
-    inline int32 inlineDataOffset() {
-        if (pic.u.vr.isConstant())
-            return SETPROP_INLINE_STORE_CONST_DATA;
-        if (pic.u.vr.isTypeKnown())
-            return SETPROP_INLINE_STORE_KTYPE_DATA;
-        return SETPROP_INLINE_STORE_DYN_DATA;
-    }
-#endif
-
-    static int32 inlineShapeOffset(ic::PICInfo &pic) {
-        return pic.setPropLabels().getInlineShapeOffset();
-    }
-
-    static int32 inlineShapeJump(ic::PICInfo &pic) {
-#if defined JS_NUNBOX32
-        return SETPROP_INLINE_SHAPE_JUMP;
-#elif defined JS_PUNBOX64
-        return inlineShapeOffset(pic) + SETPROP_INLINE_SHAPE_JUMP;
-#endif
-    }
-
-    inline int32 dslotsLoadOffset() {
-        return dslotsLoadOffset(pic);
-    }
-
-    inline int32 inlineShapeOffset() {
-        return inlineShapeOffset(pic);
-    }
-
-    inline int32 inlineShapeJump() {
-        return inlineShapeJump(pic);
-    }
-
   public:
     SetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
                     VoidStubPIC stub)
       : PICStubCompiler("setprop", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
         obj(obj), atom(atom), lastStubSecondShapeGuard(pic.secondShapeGuard)
     { }
 
     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
     {
-        repatcher.repatchLEAToLoadPtr(pic.fastPathRejoin.instructionAtOffset(dslotsLoadOffset(pic)));
-        repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(
-                           pic.shapeGuard + inlineShapeOffset(pic)),
+        SetPropLabels &labels = pic.setPropLabels();
+        repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin, pic.u.vr));
+        repatcher.repatch(labels.getInlineShapeData(pic.fastPathStart, pic.shapeGuard),
                           int32(JSObjectMap::INVALID_SHAPE));
-        repatcher.relink(pic.fastPathStart.jumpAtOffset(
-                          pic.shapeGuard + inlineShapeJump(pic)),
+        repatcher.relink(labels.getInlineShapeJump(pic.fastPathStart, pic.shapeGuard),
                          pic.slowPathStart);
 
         FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, ic::SetProp));
         repatcher.relink(pic.slowPathCall, target);
     }
 
     LookupStatus patchInline(const Shape *shape, bool inlineSlot)
     {
         JS_ASSERT(!pic.inlinePathPatched);
         JaegerSpew(JSpew_PICs, "patch setprop inline at %p\n", pic.fastPathStart.executableAddress());
 
         Repatcher repatcher(f.jit());
+        SetPropLabels &labels = pic.setPropLabels();
 
         int32 offset;
         if (inlineSlot) {
-            JSC::CodeLocationInstruction istr;
-            istr = pic.fastPathRejoin.instructionAtOffset(dslotsLoadOffset());
+            CodeLocationInstruction istr = labels.getDslotsLoad(pic.fastPathRejoin, pic.u.vr);
             repatcher.repatchLoadPtrToLEA(istr);
 
             // 
             // We've patched | mov dslots, [obj + DSLOTS_OFFSET]
             // To:           | lea fslots, [obj + DSLOTS_OFFSET]
             //
             // Because the offset is wrong, it's necessary to correct it
             // below.
@@ -288,46 +235,47 @@ class SetPropCompiler : public PICStubCo
             int32 diff = int32(JSObject::getFixedSlotOffset(0)) -
                          int32(offsetof(JSObject, slots));
             JS_ASSERT(diff != 0);
             offset  = (int32(shape->slot) * sizeof(Value)) + diff;
         } else {
             offset = shape->slot * sizeof(Value);
         }
 
-        uint32 shapeOffs = pic.shapeGuard + inlineShapeOffset();
-        repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(shapeOffs), obj->shape());
-#if defined JS_NUNBOX32
-        repatcher.repatch(pic.fastPathRejoin.dataLabel32AtOffset(inlineTypeOffset()), offset + 4);
-        repatcher.repatch(pic.fastPathRejoin.dataLabel32AtOffset(inlineDataOffset()), offset);
-#elif defined JS_PUNBOX64
-        repatcher.repatch(pic.fastPathRejoin.dataLabel32AtOffset(SETPROP_INLINE_STORE_VALUE), offset);
-#endif
+        repatcher.repatch(labels.getInlineShapeData(pic.fastPathStart, pic.shapeGuard),
+                          obj->shape());
+        repatcher.patchAddressOffsetForValueStore(labels.getInlineValueStore(pic.fastPathRejoin,
+                                                                             pic.u.vr),
+                                                  offset, pic.u.vr.isTypeKnown());
 
         pic.inlinePathPatched = true;
 
         return Lookup_Cacheable;
     }
 
+    int getLastStubSecondShapeGuard() const {
+        return lastStubSecondShapeGuard ? POST_INST_OFFSET(lastStubSecondShapeGuard) : 0;
+    }
+
     void patchPreviousToHere(CodeLocationLabel cs)
     {
         Repatcher repatcher(pic.lastCodeBlock(f.jit()));
         CodeLocationLabel label = pic.lastPathStart();
 
         // Patch either the inline fast path or a generated stub. The stub
         // omits the prefix of the inline fast path that loads the shape, so
         // the offsets are different.
         int shapeGuardJumpOffset;
         if (pic.stubsGenerated)
             shapeGuardJumpOffset = pic.setPropLabels().getStubShapeJumpOffset();
         else
-            shapeGuardJumpOffset = pic.shapeGuard + inlineShapeJump();
+            shapeGuardJumpOffset = pic.shapeGuard + pic.setPropLabels().getInlineShapeJumpOffset();
         repatcher.relink(label.jumpAtOffset(shapeGuardJumpOffset), cs);
-        if (lastStubSecondShapeGuard)
-            repatcher.relink(label.jumpAtOffset(lastStubSecondShapeGuard), cs);
+        if (int secondGuardOffset = getLastStubSecondShapeGuard())
+            repatcher.relink(label.jumpAtOffset(secondGuardOffset), cs);
     }
 
     LookupStatus generateStub(uint32 initialShape, const Shape *shape, bool adding, bool inlineSlot)
     {
         /* Exits to the slow path. */
         Vector<Jump, 8> slowExits(cx);
         Vector<Jump, 8> otherGuards(cx);
 
@@ -335,18 +283,20 @@ class SetPropCompiler : public PICStubCo
 
         // Shape guard.
         if (pic.shapeNeedsRemat()) {
             masm.loadShape(pic.objReg, pic.shapeReg);
             pic.shapeRegHasBaseShape = true;
         }
 
         Label start = masm.label();
-        Jump shapeGuard = masm.branch32_force32(Assembler::NotEqual, pic.shapeReg,
-                                                Imm32(initialShape));
+        DataLabel32 unused;
+        Jump shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, pic.shapeReg,
+                                                 Imm32(initialShape), unused);
+        (void) unused;
 
         Label stubShapeJumpLabel = masm.label();
 
         JS_ASSERT_IF(!shape->hasDefaultSetter(), obj->getClass() == &js_CallClass);
 
         MaybeJump skipOver;
 
         if (adding) {
@@ -513,17 +463,17 @@ class SetPropCompiler : public PICStubCo
         // This function can patch either the inline fast path for a generated
         // stub. The stub omits the prefix of the inline fast path that loads
         // the shape, so the offsets are different.
         patchPreviousToHere(cs);
 
         pic.stubsGenerated++;
         pic.updateLastPath(buffer, start);
 
-        pic.setPropLabels().setStubShapeJump(masm.differenceBetween(start, stubShapeJumpLabel));
+        pic.setPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel);
 
         if (pic.stubsGenerated == MAX_PIC_STUBS)
             disable("max stubs reached");
 
         return Lookup_Cacheable;
     }
 
     LookupStatus update()
@@ -778,22 +728,17 @@ class GetPropCompiler : public PICStubCo
       : PICStubCompiler(pic.kind == ic::PICInfo::CALL ? "callprop" : "getprop", f, script, pic,
                         JS_FUNC_TO_DATA_PTR(void *, stub)),
         obj(obj),
         atom(atom),
         lastStubSecondShapeGuard(pic.secondShapeGuard)
     { }
 
     int getLastStubSecondShapeGuard() const {
-#if defined JS_CPU_ARM
-        /* Jumps on ARM point at the beginning of the instruction. */
-        return lastStubSecondShapeGuard ? lastStubSecondShapeGuard - sizeof(JSC::ARMWord) : 0;
-#else
-        return lastStubSecondShapeGuard;
-#endif
+        return lastStubSecondShapeGuard ? POST_INST_OFFSET(lastStubSecondShapeGuard) : 0;
     }
 
     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
     {
         GetPropLabels &labels = pic.getPropLabels();
         repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin));
         repatcher.repatch(labels.getInlineShapeData(pic.getFastShapeGuard()),
                           int32(JSObjectMap::INVALID_SHAPE));
@@ -1163,17 +1108,17 @@ class GetPropCompiler : public PICStubCo
         JaegerSpew(JSpew_PICs, "generated %s stub at %p\n", type, cs.executableAddress());
 
         patchPreviousToHere(cs);
 
         pic.stubsGenerated++;
         pic.updateLastPath(buffer, start);
 
         if (setStubShapeOffset)
-            pic.getPropLabels().setStubShapeJump(masm.differenceBetween(start, stubShapeJumpLabel));
+            pic.getPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel);
 
         if (pic.stubsGenerated == MAX_PIC_STUBS)
             disable("max stubs reached");
         if (obj->isDenseArray())
             disable("dense array");
 
         return Lookup_Cacheable;
     }
--- a/js/src/methodjit/PolyIC.h
+++ b/js/src/methodjit/PolyIC.h
@@ -56,33 +56,16 @@
 namespace js {
 namespace mjit {
 namespace ic {
 
 /* Maximum number of stubs for a given callsite. */
 static const uint32 MAX_PIC_STUBS = 16;
 static const uint32 MAX_GETELEM_IC_STUBS = 17;
 
-/* SetPropCompiler */
-#if defined JS_CPU_X86
-static const int32 SETPROP_INLINE_SHAPE_JUMP       =  12; //asserted
-static const int32 SETPROP_DSLOTS_BEFORE_CONSTANT  = -23; //asserted
-static const int32 SETPROP_DSLOTS_BEFORE_KTYPE     = -19; //asserted
-static const int32 SETPROP_DSLOTS_BEFORE_DYNAMIC   = -15; //asserted
-static const int32 SETPROP_INLINE_STORE_DYN_TYPE   =  -6; //asserted
-static const int32 SETPROP_INLINE_STORE_DYN_DATA   =   0; //asserted
-static const int32 SETPROP_INLINE_STORE_KTYPE_TYPE = -10; //asserted
-static const int32 SETPROP_INLINE_STORE_KTYPE_DATA =   0; //asserted
-static const int32 SETPROP_INLINE_STORE_CONST_TYPE = -14; //asserted
-static const int32 SETPROP_INLINE_STORE_CONST_DATA =  -4; //asserted
-#elif defined JS_CPU_X64
-static const int32 SETPROP_INLINE_STORE_VALUE      =   0; //asserted
-static const int32 SETPROP_INLINE_SHAPE_JUMP       =   6; //asserted
-#endif
-
 void PurgePICs(JSContext *cx);
 
 enum LookupStatus {
     Lookup_Error = 0,
     Lookup_Uncacheable,
     Lookup_Cacheable
 };
 
--- a/js/src/methodjit/PunboxAssembler.h
+++ b/js/src/methodjit/PunboxAssembler.h
@@ -171,16 +171,31 @@ class PunboxAssembler : public JSC::Macr
     }
 
     /* Overload for constant type and constant data. */
     Label storeValueWithAddressOffsetPatch(const Value &v, Address address) {
         storeValue(v, address);
         return label();
     }
 
+    /* Overloaded for store with value remat info. */
+    Label storeValueWithAddressOffsetPatch(const ValueRemat &vr, Address address) {
+        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());
+            RegisterID data(vr.dataReg());
+            return storeValueWithAddressOffsetPatch(type, data, address);
+        }
+    }
+
     template <typename T>
     void loadTypeTag(T address, RegisterID reg) {
         loadValue(address, reg);
         convertValueToType(reg);
     }
 
     template <typename T>
     void storeTypeTag(ImmTag imm, T address) {