Bug 588021: Port GETPROP PIC for ARM. (r=dmandelin)
authorChris Leary <cdleary@mozilla.com>
Thu, 13 Jan 2011 22:40:15 -0800
changeset 60592 651254a19521152b947880ab940610f3b4415a2f
parent 60591 4989cff3af0c18b5298d53a30509a15d8d344c71
child 60593 02a47304563085c5160440e7e04e88c674aa3525
push id18037
push usercleary@mozilla.com
push dateFri, 14 Jan 2011 17:42:55 +0000
treeherdermozilla-central@4e0501a0c5e5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdmandelin
bugs588021
milestone2.0b10pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 588021: Port GETPROP PIC for ARM. (r=dmandelin)
js/src/configure.in
js/src/methodjit/BaseCompiler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/ICLabels.h
js/src/methodjit/ICRepatcher.h
js/src/methodjit/NunboxAssembler.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/PolyIC.h
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2908,33 +2908,37 @@ 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
     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
     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
     AC_DEFINE(JS_CPU_ARM)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 sparc*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=Sparc
     AC_DEFINE(JS_CPU_SPARC)
     ;;
@@ -2970,16 +2974,36 @@ fi
 if test "$ENABLE_MONOIC"; then
     AC_DEFINE(JS_MONOIC)
 fi
 
 if test "$ENABLE_POLYIC"; then
     AC_DEFINE(JS_POLYIC)
 fi
 
+if test "$ENABLE_POLYIC_GETPROP"; then
+    AC_DEFINE(JS_POLYIC_GETPROP)
+fi
+
+if test "$ENABLE_POLYIC_SETPROP"; then
+    AC_DEFINE(JS_POLYIC_SETPROP)
+fi
+
+if test "$ENABLE_POLYIC_NAME"; then
+    AC_DEFINE(JS_POLYIC_SETPROP)
+fi
+
+if test "$ENABLE_POLYIC_BIND"; then
+    AC_DEFINE(JS_POLYIC_SETPROP)
+fi
+
+if test "$ENABLE_POLYIC_ELEM"; then
+    AC_DEFINE(JS_POLYIC_ELEM)
+fi
+
 if test "$ENABLE_METHODJIT_SPEW"; then
     AC_DEFINE(JS_METHODJIT_SPEW)
 fi
 
 if test "$ENABLE_TRACEJIT"; then
 
 AC_DEFINE(FEATURE_NANOJIT)
 AC_DEFINE(JS_TRACER)
--- a/js/src/methodjit/BaseCompiler.h
+++ b/js/src/methodjit/BaseCompiler.h
@@ -64,20 +64,26 @@ struct MacroAssemblerTypedefs {
     typedef JSC::MacroAssembler::Jump Jump;
     typedef JSC::MacroAssembler::JumpList JumpList;
     typedef JSC::MacroAssembler::Call Call;
     typedef JSC::MacroAssembler::DataLabelPtr DataLabelPtr;
     typedef JSC::MacroAssembler::DataLabel32 DataLabel32;
     typedef JSC::FunctionPtr FunctionPtr;
     typedef JSC::RepatchBuffer RepatchBuffer;
     typedef JSC::CodeLocationLabel CodeLocationLabel;
+    typedef JSC::CodeLocationDataLabel32 CodeLocationDataLabel32;
+    typedef JSC::CodeLocationJump CodeLocationJump;
     typedef JSC::CodeLocationCall CodeLocationCall;
+    typedef JSC::CodeLocationInstruction CodeLocationInstruction;
     typedef JSC::ReturnAddressPtr ReturnAddressPtr;
     typedef JSC::MacroAssemblerCodePtr MacroAssemblerCodePtr;
     typedef JSC::JITCode JITCode;
+#if defined JS_CPU_ARM
+    typedef JSC::ARMWord ARMWord;
+#endif
 };
 
 class BaseCompiler : public MacroAssemblerTypedefs
 {
   protected:
     JSContext *cx;
 
   public:
@@ -190,58 +196,87 @@ class LinkerHelper : public JSC::LinkBuf
  * ICs perform repatching on the inline (fast) path by knowing small and
  * generally fixed code location offset values where the patchable instructions
  * live. Dumping a huge constant pool into the middle of an IC's inline path
  * makes the distance between emitted instructions potentially variable and/or
  * large, which makes the IC offsets invalid. We must reserve contiguous space
  * up front to prevent this from happening.
  */
 #ifdef JS_CPU_ARM
+template <size_t reservedSpace>
 class AutoReserveICSpace {
     typedef Assembler::Label Label;
-    static const size_t reservedSpace = 68;
 
     Assembler           &masm;
 #ifdef DEBUG
     Label               startLabel;
+    bool                didCheck;
 #endif
 
   public:
     AutoReserveICSpace(Assembler &masm) : masm(masm) {
         masm.ensureSpace(reservedSpace);
 #ifdef DEBUG
+        didCheck = false;
+
         startLabel = masm.label();
 
         /* Assert that the constant pool is not flushed until we reach a safe point. */
         masm.allowPoolFlush(false);
 
         JaegerSpew(JSpew_Insns, " -- BEGIN CONSTANT-POOL-FREE REGION -- \n");
 #endif
     }
 
-    ~AutoReserveICSpace() {
+    /* Allow manual IC space checks so that non-patchable code at the end of an IC section can be
+     * free to use constant pools. */
+    void check() {
 #ifdef DEBUG
+        JS_ASSERT(!didCheck);
+        didCheck = true;
+
         Label endLabel = masm.label();
         int spaceUsed = masm.differenceBetween(startLabel, endLabel);
 
         /* Spew the space used, to help tuning of reservedSpace. */
         JaegerSpew(JSpew_Insns,
                    " -- END CONSTANT-POOL-FREE REGION: %u bytes used of %u reserved. -- \n",
                    spaceUsed, reservedSpace);
 
         /* Assert that we didn't emit more code than we protected. */
         JS_ASSERT(spaceUsed >= 0);
         JS_ASSERT(size_t(spaceUsed) <= reservedSpace);
 
         /* Allow the pool to be flushed. */
         masm.allowPoolFlush(true);
 #endif
     }
+
+    ~AutoReserveICSpace() {
+#ifdef DEBUG
+        /* Automatically check the IC space if we didn't already do it manually. */
+        if (!didCheck) {
+            check();
+        }
+#endif
+    }
 };
-# define RESERVE_IC_SPACE(__masm) AutoReserveICSpace arics(__masm)
+
+# define RESERVE_IC_SPACE(__masm)       AutoReserveICSpace<80> arics(__masm)
+
+/* The OOL path can need a lot of space because we save and restore a lot of registers. The actual
+ * sequene varies. However, dumping the literal pool before an OOL block is probably a good idea
+ * anyway, as we branch directly to the start of the block from the fast path. */
+# define RESERVE_OOL_SPACE(__masm)      AutoReserveICSpace<256> arics_ool(__masm)
+
+/* Allow the OOL patch to be checked before object destruction. Often, non-patchable epilogues or
+ * rejoining sequences are emitted, and it isn't necessary to protect these from literal pools. */
+# define CHECK_OOL_SPACE()              arics_ool.check()
 #else
-# define RESERVE_IC_SPACE(__masm) /* Nothing. */
+# define RESERVE_IC_SPACE(__masm)       /* Do nothing. */
+# define RESERVE_OOL_SPACE(__masm)      /* Do nothing. */
+# define CHECK_OOL_SPACE()              /* Do nothing. */
 #endif
 
 } /* namespace js */
 } /* namespace mjit */
 
 #endif
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -2964,17 +2964,19 @@ mjit::Compiler::passMICAddress(MICGenInf
 #endif
 
 #if defined JS_POLYIC
 void
 mjit::Compiler::passICAddress(BaseICInfo *ic)
 {
     ic->paramAddr = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
 }
-
+#endif
+
+#if defined JS_POLYIC_GETPROP
 bool
 mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
 {
     FrameEntry *top = frame.peek(-1);
 
     /* If the incoming type will never PIC, take slow path. */
     if (top->isTypeKnown() && top->getKnownType() != JSVAL_TYPE_OBJECT) {
         JS_ASSERT_IF(atom == cx->runtime->atomState.lengthAtom,
@@ -2990,31 +2992,31 @@ mjit::Compiler::jsop_getprop(JSAtom *ato
      */
     RegisterID objReg = Registers::ReturnReg;
     RegisterID shapeReg = Registers::ReturnReg;
     if (atom == cx->runtime->atomState.lengthAtom) {
         objReg = frame.copyDataIntoReg(top);
         shapeReg = frame.allocReg();
     }
 
+    RESERVE_IC_SPACE(masm);
+
     PICGenInfo pic(ic::PICInfo::GET, JSOp(*PC), usePropCache);
 
     /* Guard that the type is an object. */
-    Jump typeCheck;
+    Label typeCheck;
     if (doTypeCheck && !top->isTypeKnown()) {
         RegisterID reg = frame.tempRegForType(top);
         pic.typeReg = reg;
 
         /* Start the hot path where it's easy to patch it. */
         pic.fastPathStart = masm.label();
         Jump j = masm.testObject(Assembler::NotEqual, reg);
-
-        /* GETPROP_INLINE_TYPE_GUARD is used to patch the jmp, not cmp. */
+        typeCheck = masm.label();
         RETURN_IF_OOM(false);
-        JS_ASSERT(masm.differenceBetween(pic.fastPathStart, masm.label()) == GETPROP_INLINE_TYPE_GUARD);
 
         pic.typeCheck = stubcc.linkExit(j, Uses(1));
         pic.hasTypeCheck = true;
     } else {
         pic.fastPathStart = masm.label();
         pic.hasTypeCheck = false;
         pic.typeReg = Registers::ReturnReg;
     }
@@ -3030,71 +3032,64 @@ mjit::Compiler::jsop_getprop(JSAtom *ato
     /* Guard on shape. */
     masm.loadShape(objReg, shapeReg);
     pic.shapeGuard = masm.label();
 
     DataLabel32 inlineShapeLabel;
     Jump j = masm.branch32WithPatch(Assembler::NotEqual, shapeReg,
                                     Imm32(int32(JSObjectMap::INVALID_SHAPE)),
                                     inlineShapeLabel);
-    DBGLABEL(dbgInlineShapeJump);
-
+    Label inlineShapeJump = masm.label();
+
+    RESERVE_OOL_SPACE(stubcc.masm);
     pic.slowPathStart = stubcc.linkExit(j, Uses(1));
 
     stubcc.leave();
     passICAddress(&pic);
     pic.slowPathCall = OOL_STUBCALL(ic::GetProp);
-
-    /* Load dslots. */
-    Label dslotsLoadLabel = masm.label();
-    masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
+    CHECK_OOL_SPACE();
+
+    /* Load the base slot address. */
+    Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)),
+                                                               objReg);
 
     /* Copy the slot value to the expression stack. */
     Address slot(objReg, 1 << 24);
     frame.pop();
 
-#if defined JS_NUNBOX32
-    masm.loadTypeTag(slot, shapeReg);
-    Label typeLoad = masm.label();
-
-    masm.loadPayload(slot, objReg);
-    Label dataLoad = masm.label();
-#elif defined JS_PUNBOX64
-    Label inlineValueLoadLabel = masm.loadValueAsComponents(slot, shapeReg, objReg);
-#endif
+    Label fastValueLoad = masm.loadValueWithAddressOffsetPatch(slot, shapeReg, objReg);
     pic.fastPathRejoin = masm.label();
 
     RETURN_IF_OOM(false);
 
+    /* Initialize op labels. */
     GetPropLabels &labels = pic.getPropLabels();
-    labels.setDslotsLoadOffset(masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel));
-    labels.setInlineShapeOffset(masm.differenceBetween(pic.shapeGuard, inlineShapeLabel));
-
-#if defined JS_NUNBOX32
-    labels.setTypeLoad(masm.differenceBetween(pic.fastPathRejoin, typeLoad));
-    labels.setDataLoad(masm.differenceBetween(pic.fastPathRejoin, dataLoad));
-
-    JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
-#elif defined JS_PUNBOX64
-    labels.setValueLoad(masm.differenceBetween(pic.fastPathRejoin, inlineValueLoadLabel));
-
-    JS_ASSERT(masm.differenceBetween(inlineShapeLabel, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
+    labels.setDslotsLoad(masm, pic.fastPathRejoin, dslotsLoadLabel);
+    labels.setInlineShapeData(masm, pic.shapeGuard, inlineShapeLabel);
+
+    labels.setValueLoad(masm, pic.fastPathRejoin, fastValueLoad);
+    if (pic.hasTypeCheck)
+        labels.setInlineTypeJump(masm, pic.fastPathStart, typeCheck);
+#ifdef JS_CPU_X64
+    labels.setInlineShapeJump(masm, inlineShapeLabel, inlineShapeJump);
+#else
+    labels.setInlineShapeJump(masm, pic.shapeGuard, inlineShapeJump);
 #endif
 
-    /* GETPROP_INLINE_TYPE_GUARD's validity is asserted above. */
-
     pic.objReg = objReg;
     frame.pushRegs(shapeReg, objReg);
 
     stubcc.rejoin(Changes(1));
 
     pics.append(pic);
     return true;
 }
-
+#endif /* JS_POLYIC_GETPROP */
+
+#if defined JS_POLYIC_CALLPROP
 bool
 mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
 {
     FrameEntry *top = frame.peek(-1);
 
     /*
      * These two must be loaded first. The objReg because the string path
      * wants to read it, and the shapeReg because it could cause a spill that
@@ -3166,42 +3161,30 @@ mjit::Compiler::jsop_callprop_generic(JS
 
     /* Load dslots. */
     Label dslotsLoadLabel = masm.label();
     masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
 
     /* Copy the slot value to the expression stack. */
     Address slot(objReg, 1 << 24);
 
-#if defined JS_NUNBOX32
-    masm.loadTypeTag(slot, shapeReg);
-    Label typeLoad = masm.label();
-
-    masm.loadPayload(slot, objReg);
-    Label dataLoad = masm.label();
-#elif defined JS_PUNBOX64
-    Label inlineValueLoadLabel = masm.loadValueAsComponents(slot, shapeReg, objReg);
-#endif
+    Label fastValueLoad = masm.loadValueWithAddressOffsetPatch(slot, shapeReg, objReg);
     pic.fastPathRejoin = masm.label();
 
     /* Assert correctness of hardcoded offsets. */
     RETURN_IF_OOM(false);
     JS_ASSERT(masm.differenceBetween(pic.fastPathStart, dbgInlineTypeGuard) == GETPROP_INLINE_TYPE_GUARD);
 
     GetPropLabels &labels = pic.getPropLabels();
     labels.setDslotsLoadOffset(masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel));
     labels.setInlineShapeOffset(masm.differenceBetween(pic.shapeGuard, inlineShapeLabel));
+    labels.setValueLoad(masm, pic.fastPathRejoin, fastValueLoad);
 #if defined JS_NUNBOX32
-    labels.setTypeLoad(masm.differenceBetween(pic.fastPathRejoin, typeLoad));
-    labels.setDataLoad(masm.differenceBetween(pic.fastPathRejoin, dataLoad));
-
     JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
 #elif defined JS_PUNBOX64
-    labels.setValueLoad(masm.differenceBetween(pic.fastPathRejoin, inlineValueLoadLabel));
-
     JS_ASSERT(masm.differenceBetween(inlineShapeLabel, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
 #endif
 
     stubcc.rejoin(Changes(2));
     pics.append(pic);
 
     return true;
 }
@@ -3304,25 +3287,17 @@ mjit::Compiler::jsop_callprop_obj(JSAtom
 
     /* Load dslots. */
     Label dslotsLoadLabel = masm.label();
     masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
 
     /* Copy the slot value to the expression stack. */
     Address slot(objReg, 1 << 24);
 
-#if defined JS_NUNBOX32
-    masm.loadTypeTag(slot, shapeReg);
-    Label dbgTypeLoad = masm.label();
-
-    masm.loadPayload(slot, objReg);
-    Label dbgDataLoad = masm.label();
-#elif defined JS_PUNBOX64
-    Label inlineValueLoadLabel = masm.loadValueAsComponents(slot, shapeReg, objReg);
-#endif
+    Label fastValueLoad = masm.loadValueWithAddressOffsetPatch(slot, shapeReg, objReg);
 
     pic.fastPathRejoin = masm.label();
     pic.objReg = objReg;
 
     /*
      * 1) Dup the |this| object.
      * 2) Push the property value onto the stack.
      * 3) Move the value below the dup'd |this|, uncopying it. This could
@@ -3339,24 +3314,21 @@ mjit::Compiler::jsop_callprop_obj(JSAtom
      * Assert correctness of hardcoded offsets.
      * No type guard: type is asserted.
      */
     RETURN_IF_OOM(false);
 
     GetPropLabels &labels = pic.getPropLabels();
     labels.setDslotsLoadOffset(masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel));
     labels.setInlineShapeOffset(masm.differenceBetween(pic.shapeGuard, inlineShapeLabel));
+    labels.setValueLoad(masm, pic.fastPathRejoin, fastValueLoad);
+
 #if defined JS_NUNBOX32
-    labels.setTypeLoad(masm.differenceBetween(pic.fastPathRejoin, dbgTypeLoad));
-    labels.setDataLoad(masm.differenceBetween(pic.fastPathRejoin, dbgDataLoad));
-
     JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
 #elif defined JS_PUNBOX64
-    labels.setValueLoad(masm.differenceBetween(pic.fastPathRejoin, inlineValueLoadLabel));
-
     JS_ASSERT(masm.differenceBetween(inlineShapeLabel, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
 #endif
 
     stubcc.rejoin(Changes(2));
     pics.append(pic);
 
     return true;
 }
@@ -3372,17 +3344,19 @@ mjit::Compiler::jsop_callprop(JSAtom *at
             return jsop_callprop_str(atom);
         return jsop_callprop_slow(atom);
     }
 
     if (top->isTypeKnown())
         return jsop_callprop_obj(atom);
     return jsop_callprop_generic(atom);
 }
-
+#endif /* JS_POLYIC_CALLPROP */
+
+#ifdef JS_POLYIC_SETPROP
 bool
 mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
 {
     FrameEntry *lhs = frame.peek(-2);
     FrameEntry *rhs = frame.peek(-1);
 
     /* If the incoming type will never PIC, take slow path. */
     if (lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_OBJECT) {
@@ -3511,17 +3485,19 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
         JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgAfterValueStore) == SETPROP_INLINE_STORE_DYN_DATA);
         JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgDslots) == SETPROP_DSLOTS_BEFORE_DYNAMIC);
     }
 #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);
 
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.allocReg();
     pic.typeReg = Registers::ReturnReg;
@@ -3588,16 +3564,19 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
     JS_ASSERT(masm.differenceBetween(pic.fastPathStart, dbgJumpOffset) == SCOPENAME_JUMP_OFFSET);
 
     stubcc.rejoin(Changes(1));
 
     pics.append(pic);
     return true;
 }
 
+#endif /* JSOP_POLYIC_NAME */
+
+#ifdef JS_POLYIC_BIND
 void
 mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
 {
     PICGenInfo pic(ic::PICInfo::BIND, JSOp(*PC), usePropCache);
 
     // This code does not check the frame flags to see if scopeChain has been
     // set. Rather, it relies on the up-front analysis statically determining
     // whether BINDNAME can be used, which reifies the scope chain at the
@@ -3636,53 +3615,61 @@ mjit::Compiler::jsop_bindname(JSAtom *at
 
     BindNameLabels &labels = pic.bindNameLabels();
     labels.setInlineJumpOffset(masm.differenceBetween(pic.shapeGuard, inlineJumpOffset));
 
     stubcc.rejoin(Changes(1));
 
     pics.append(pic);
 }
-
-#else /* JS_POLYIC */
-
+#endif /* JS_POLYIC_BIND */
+
+#if !defined JS_POLYIC_NAME
 void
 mjit::Compiler::jsop_name(JSAtom *atom)
 {
     prepareStubCall(Uses(0));
     INLINE_STUBCALL(stubs::Name);
     frame.pushSynced();
 }
 
 bool
 mjit::Compiler::jsop_xname(JSAtom *atom)
 {
     return jsop_getprop(atom);
 }
-
+#endif
+
+#if !defined JS_POLYIC_GETPROP
 bool
 mjit::Compiler::jsop_getprop(JSAtom *atom, bool typecheck, bool usePropCache)
 {
     jsop_getprop_slow(atom, usePropCache);
     return true;
 }
-
+#endif
+
+#if !defined JS_POLYIC_CALLPROP
 bool
 mjit::Compiler::jsop_callprop(JSAtom *atom)
 {
     return jsop_callprop_slow(atom);
 }
-
+#endif
+
+#if !defined JS_POLYIC_SETPROP
 bool
 mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
 {
     jsop_setprop_slow(atom, usePropCache);
     return true;
 }
-
+#endif
+
+#if !defined JS_POLYIC_BIND
 void
 mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
 {
     RegisterID reg = frame.allocReg();
     Address scopeChain(JSFrameReg, JSStackFrame::offsetOfScopeChain());
     masm.loadPtr(scopeChain, reg);
 
     Address address(reg, offsetof(JSObject, parent));
@@ -4350,19 +4337,19 @@ mjit::Compiler::jsop_getgname(uint32 ind
 
     /* Garbage value. */
     uint32 slot = 1 << 24;
 
     masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
     Address address(objReg, slot);
     
     /* Allocate any register other than objReg. */
-    RegisterID dreg = frame.allocReg();
+    RegisterID treg = frame.allocReg();
     /* After dreg is loaded, it's safe to clobber objReg. */
-    RegisterID treg = objReg;
+    RegisterID dreg = objReg;
 
     mic.load = masm.loadValueWithAddressOffsetPatch(address, treg, dreg);
 
     frame.pushRegs(treg, dreg);
 
     stubcc.rejoin(Changes(1));
     mics.append(mic);
 
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1281,17 +1281,17 @@ mjit::Compiler::jsop_setelem(bool popGua
     } else {
         BaseIndex slot(ic.objReg, ic.key.reg(), Assembler::JSVAL_SCALE);
         ic.holeGuard = masm.guardNotHole(slot);
         masm.storeValue(ic.vr, slot);
     }
     stubcc.linkExitDirect(ic.holeGuard, ic.slowPathStart);
 
     stubcc.leave();
-#ifdef JS_POLYIC
+#if defined JS_POLYIC && defined JS_POLYIC_SETELEM
     passICAddress(&ic);
     ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(ic::SetElement));
 #else
     OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem));
 #endif
 
     ic.fastPathRejoin = masm.label();
 
@@ -1321,32 +1321,32 @@ mjit::Compiler::jsop_setelem(bool popGua
     } else if (!ic.vr.isConstant()) {
         ic.volatileMask |= Registers::maskReg(ic.vr.dataReg());
     }
 
     frame.freeReg(ic.objReg);
     frame.shimmy(2);
     stubcc.rejoin(Changes(2));
 
-#ifdef JS_POLYIC
+#if defined JS_POLYIC && defined JS_POLYIC_SETELEM
     if (!setElemICs.append(ic))
         return false;
 #endif
 
     return true;
 }
 
 static inline bool
 IsCacheableGetElem(FrameEntry *obj, FrameEntry *id)
 {
     if (obj->isTypeKnown() && obj->getKnownType() != JSVAL_TYPE_OBJECT)
         return false;
     if (id->isTypeKnown() &&
         !(id->getKnownType() == JSVAL_TYPE_INT32
-#ifdef JS_POLYIC
+#if defined JS_POLYIC && defined JS_POLYIC_GETELEM
           || id->getKnownType() == JSVAL_TYPE_STRING
 #endif
          )) {
         return false;
     }
 
     if (id->isTypeKnown() && id->getKnownType() == JSVAL_TYPE_INT32 && id->isConstant() &&
         id->getValue().toInt32() < 0) {
@@ -1466,17 +1466,17 @@ mjit::Compiler::jsop_getelem(bool isCall
         // fall back to a slow path.
         ic.claspGuard = masm.jump();
         stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart);
     }
 
     stubcc.leave();
     if (objTypeGuard.isSet())
         objTypeGuard.get().linkTo(stubcc.masm.label(), &stubcc.masm);
-#ifdef JS_POLYIC
+#if defined JS_POLYIC && defined JS_POLYIC_GETELEM
     passICAddress(&ic);
     if (isCall)
         ic.slowPathCall = OOL_STUBCALL(ic::CallElement);
     else
         ic.slowPathCall = OOL_STUBCALL(ic::GetElement);
 #else
     if (isCall)
         ic.slowPathCall = OOL_STUBCALL(stubs::CallElem);
@@ -1488,17 +1488,17 @@ mjit::Compiler::jsop_getelem(bool isCall
 
     frame.popn(2);
     frame.pushRegs(ic.typeReg, ic.objReg);
     if (isCall)
         frame.pushSynced();
 
     stubcc.rejoin(Changes(2));
 
-#ifdef JS_POLYIC
+#if defined JS_POLYIC && defined JS_POLYIC_GETELEM
     if (!getElemICs.append(ic))
         return false;
 #endif
 
     return true;
 }
 
 static inline bool
--- a/js/src/methodjit/ICLabels.h
+++ b/js/src/methodjit/ICLabels.h
@@ -43,127 +43,210 @@
 #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"
 
 class ICOffsetInitializer {
   public:
     ICOffsetInitializer();
 };
 
 namespace js {
 namespace mjit {
 namespace ic {
 
+/*
+ * On x64 and ARM, we record offsets into the labels data structures at runtime
+ * instead of using hardcoded offsets into the instruction stream, as we do on
+ * x86.
+ *
+ * This is done on x64 because of variable-width instruction encoding when
+ * using the extended register set. It is done on ARM for ease of
+ * implementation.
+ */
+
 #if defined JS_CPU_X64 || defined JS_CPU_ARM
-/*
- * On x64 and ARM, we create offsets dynamically instead of using hardcoded
- * offsets into the instruction stream. This is done on x64 because of
- * variable-width instruction encoding when using the extended register set and
- * it is done on ARM for expediency of implementation.
- */
 # define JS_HAS_IC_LABELS
 #endif
 
+# define JS_POLYIC_OFFSET_BITS 8
+
 /* GetPropCompiler */
-struct GetPropLabels {
+struct GetPropLabels : MacroAssemblerTypedefs {
     friend class ::ICOffsetInitializer;
 
+    void setValueLoad(MacroAssembler &masm, Label fastPathRejoin, Label fastValueLoad) {
+        int offset = masm.differenceBetween(fastPathRejoin, fastValueLoad);
+#ifdef JS_HAS_IC_LABELS
+        inlineValueLoadOffset = offset;
+#endif
+        /* 
+         * Note: the offset between the type and data loads for x86 is asserted
+         * in NunboxAssembler::loadValueWithAddressOffsetPatch.
+         */
+        JS_ASSERT(offset == inlineValueLoadOffset);
+    }
+
+    CodeLocationLabel getValueLoad(CodeLocationLabel fastPathRejoin) {
+        return fastPathRejoin.labelAtOffset(inlineValueLoadOffset);
+    }
+
+    void setDslotsLoad(MacroAssembler &masm, Label fastPathRejoin, Label dslotsLoad) {
+        int offset = masm.differenceBetween(fastPathRejoin, dslotsLoad);
+        setDslotsLoadOffset(offset);
+    }
+
+    CodeLocationInstruction getDslotsLoad(CodeLocationLabel fastPathRejoin) {
+        return fastPathRejoin.instructionAtOffset(getDslotsLoadOffset());
+    }
+
+    void setInlineShapeData(MacroAssembler &masm, Label shapeGuard, DataLabel32 inlineShape) {
+        int offset = masm.differenceBetween(shapeGuard, inlineShape);
+        setInlineShapeOffset(offset);
+    }
+
+    CodeLocationDataLabel32 getInlineShapeData(CodeLocationLabel fastShapeGuard) {
+        return fastShapeGuard.dataLabel32AtOffset(getInlineShapeOffset());
+    }
+
+    /*
+     * 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));
+    }
+
+    CodeLocationJump getInlineShapeJump(CodeLocationLabel fastShapeGuard) {
+        return fastShapeGuard.jumpAtOffset(getInlineShapeJumpOffset());
+    }
+
+    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
+    }
+
+    /* Offset-based interface */
+
     void setDslotsLoadOffset(int offset) {
 #ifdef JS_HAS_IC_LABELS
         dslotsLoadOffset = offset;
 #endif
         JS_ASSERT(offset == dslotsLoadOffset);
     }
 
     void setInlineShapeOffset(int offset) {
 #ifdef JS_HAS_IC_LABELS
         inlineShapeOffset = offset;
 #endif
         JS_ASSERT(offset == inlineShapeOffset);
     }
     
     void setStubShapeJump(int offset) {
 #ifdef JS_HAS_IC_LABELS
-        stubShapeJump = offset;
+        stubShapeJumpOffset = offset;
 #endif
-        JS_ASSERT(offset == stubShapeJump);
+        JS_ASSERT(offset == stubShapeJumpOffset);
+    }
+
+    int getInlineShapeJumpOffset() {
+#if defined JS_CPU_X86
+        return INLINE_SHAPE_JUMP;
+#elif defined JS_CPU_X64
+        return getInlineShapeOffset() + INLINE_SHAPE_JUMP;
+#elif defined JS_CPU_ARM
+        return INLINE_SHAPE_JUMP - sizeof(ARMWord);
+#endif
     }
 
-#if defined JS_NUNBOX32
-    void setTypeLoad(int offset) {
-# if defined JS_HAS_IC_LABELS
-        inlineTypeLoad = offset;
-# endif
-        JS_ASSERT(offset == inlineTypeLoad);
-    }
-    void setDataLoad(int offset) {
-# if defined JS_HAS_IC_LABELS
-        inlineDataLoad = offset;
-# endif
-        JS_ASSERT(offset == inlineDataLoad);
+    void setInlineShapeJumpOffset(int offset) {
+        JS_ASSERT(INLINE_SHAPE_JUMP == offset);
     }
-    JSC::CodeLocationDataLabel32 getTypeLoad(JSC::CodeLocationLabel start) {
-        return start.dataLabel32AtOffset(inlineTypeLoad);
-    }
-    JSC::CodeLocationDataLabel32 getDataLoad(JSC::CodeLocationLabel start) {
-        return start.dataLabel32AtOffset(inlineDataLoad);
+
+    int getInlineTypeJumpOffset() {
+#if defined JS_CPU_X86 || defined JS_CPU_X64
+        return INLINE_TYPE_JUMP;
+#elif defined JS_CPU_ARM
+        return inlineTypeJumpOffset;
+#endif
     }
-#elif defined JS_PUNBOX64
-    void setValueLoad(int offset) {
-# if defined JS_HAS_IC_LABELS
-        inlineValueLoad = offset;
-# endif
-        JS_ASSERT(offset == inlineValueLoad);
-    }
-    JSC::CodeLocationDataLabel32 getValueLoad(JSC::CodeLocationLabel start) {
-        return start.dataLabel32AtOffset(inlineValueLoad);
-    }
+
+    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;
+        JS_ASSERT(offset == inlineTypeJumpOffset);
 #endif
+     }
 
     int getInlineShapeOffset() {
         return inlineShapeOffset;
     }
     int getDslotsLoadOffset() {
         return dslotsLoadOffset;
     }
-    int getStubShapeJump() {
-        return stubShapeJump;
+    int getStubShapeJumpOffset() {
+#if defined JS_CPU_X86 || defined JS_CPU_X64
+        return stubShapeJumpOffset;
+#elif defined JS_CPU_ARM
+        return stubShapeJumpOffset - sizeof(ARMWord);
+#endif
     }
 
   private:
     /* Offset from storeBack to beginning of 'mov dslots, addr' */
     int32 dslotsLoadOffset : 8;
 
     /* Offset from shapeGuard to end of shape comparison. */
     int32 inlineShapeOffset : 8;
 
     /* Offset from storeBack to end of value load. */
-#ifdef JS_NUNBOX32
-    int32 inlineTypeLoad    : 8;
-    int32 inlineDataLoad    : 8;
-#elif JS_PUNBOX64
-    int32 inlineValueLoad   : 8;
-#endif
+    int32 inlineValueLoadOffset : 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 int32 INLINE_SHAPE_JUMP = 12;
+    static const int32 INLINE_TYPE_JUMP = 12;
+#elif defined JS_CPU_X64
+    static const int32 INLINE_SHAPE_JUMP = 6;
+    static const int32 INLINE_TYPE_JUMP = 19;
+#elif defined JS_CPU_ARM
+    /* Offset from the shape guard start to the shape guard jump. */
+    static const int32 INLINE_SHAPE_JUMP = 12;
+
+    /* Offset from the fast path to the type guard jump. */
+    int32 inlineTypeJumpOffset : 8;
+#endif
 };
 
 /* SetPropCompiler */
 struct SetPropLabels {
     friend class ::ICOffsetInitializer;
 
 #ifdef JS_PUNBOX64
     void setDslotsLoadOffset(int offset) {
@@ -201,17 +284,17 @@ struct SetPropLabels {
         return inlineShapeOffset;
     }
     int getStubShapeJump() {
         return stubShapeJump;
     }
 
   private:
 #ifdef JS_PUNBOX64
-    /* Offset from storeBack to beginning of 'mov dslots, addr' */
+    /* Offset from storeBack to beginning of 'mov dslots, addr'. */
     int32 dslotsLoadOffset : 8;
 #endif
 
     /* Offset from shapeGuard to end of shape comparison. */
     int32 inlineShapeOffset : 8;
 
     /* 
      * Offset from lastStubStart to end of shape jump.
--- a/js/src/methodjit/ICRepatcher.h
+++ b/js/src/methodjit/ICRepatcher.h
@@ -93,24 +93,24 @@ class Repatcher : public JSC::RepatchBuf
 #endif
     }
 
     /* Patch the offset of a Value load emitted by loadValueWithAddressOffsetPatch. */
     void patchAddressOffsetForValueLoad(CodeLocationLabel label, uint32 offset) {
 #if defined JS_CPU_X64 || defined JS_CPU_ARM
         repatch(label.dataLabel32AtOffset(0), offset);
 #elif defined JS_CPU_X86
-        static const unsigned LOAD_DATA_OFFSET = 6;
-        static const unsigned LOAD_TYPE_OFFSET = 12;
+        static const unsigned LOAD_TYPE_OFFSET = 6;
+        static const unsigned LOAD_DATA_OFFSET = 12;
 
         /*
          * We have the following sequence to patch:
          *
+         *      mov     <offset+4>($base), %<type>
          *      mov     <offset+0>($base), %<data>
-         *      mov     <offset+4>($base), %<type>
          */
         repatch(label.dataLabel32AtOffset(LOAD_DATA_OFFSET), offset);
         repatch(label.dataLabel32AtOffset(LOAD_TYPE_OFFSET), offset + 4);
 #else
 # error
 #endif
     }
 
--- a/js/src/methodjit/NunboxAssembler.h
+++ b/js/src/methodjit/NunboxAssembler.h
@@ -161,34 +161,34 @@ class NunboxAssembler : public JSC::Macr
     }
 
     /*
      * Load a (64b) js::Value from 'address' into 'type' and 'payload', and
      * return a label which can be used by
      * ICRepatcher::patchAddressOffsetForValueLoad to patch the address'
      * offset.
      *
-     * The type register is guaranteed to be clobbered last. (This makes the
-     * base register for the address reusable as 'treg'.)
+     * The data register is guaranteed to be clobbered last. (This makes the
+     * base register for the address reusable as 'dreg'.)
      */
     Label loadValueWithAddressOffsetPatch(Address address, RegisterID treg, RegisterID dreg) {
-        JS_ASSERT(address.base != dreg); /* dreg is clobbered first. */
+        JS_ASSERT(address.base != treg); /* treg is clobbered first. */
 
         Label start = label();
 #if defined JS_CPU_X86
         /*
          * On x86 there are two loads to patch and they both encode the offset
          * in-line.
          */
+        loadTypeTag(address, treg);
+        DBGLABEL_NOMASM(endType);
         loadPayload(address, dreg);
         DBGLABEL_NOMASM(endPayload);
-        loadTypeTag(address, treg);
-        DBGLABEL_NOMASM(endType);
-        JS_ASSERT(differenceBetween(start, endPayload) == 6);
-        JS_ASSERT(differenceBetween(endPayload, endType) == 6);
+        JS_ASSERT(differenceBetween(start, endType) == 6);
+        JS_ASSERT(differenceBetween(endType, endPayload) == 6);
         return start;
 #elif defined JS_CPU_ARM
         /* 
          * On ARM, the first instruction loads the offset from a literal pool, so the label
          * returned points at that instruction.
          */
         DataLabel32 load = load64WithAddressOffsetPatch(address, treg, dreg);
         JS_ASSERT(differenceBetween(start, load) == 0);
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -72,19 +72,18 @@ static const uint32 INLINE_PATH_LENGTH =
 #ifndef JS_HAS_IC_LABELS
 ICOffsetInitializer::ICOffsetInitializer()
 {
     {
         GetPropLabels &labels = PICInfo::getPropLabels_;
 #if defined JS_CPU_X86
         labels.dslotsLoadOffset = -15;
         labels.inlineShapeOffset = 6;
-        labels.inlineTypeLoad = -6;
-        labels.inlineDataLoad = 0;
-        labels.stubShapeJump = 12;
+        labels.stubShapeJumpOffset = 12;
+        labels.inlineValueLoadOffset = -12;
 #endif
     }
     {
         SetPropLabels &labels = PICInfo::setPropLabels_;
         labels.inlineShapeOffset = 6;
         labels.stubShapeJump = 12;
     }
     {
@@ -168,16 +167,17 @@ class PICStubCompiler : public BaseCompi
 #ifdef JS_METHODJIT_SPEW
         JaegerSpew(JSpew_PICs, "%s %s: %s (%s: %d)\n",
                    type, event, op, script->filename,
                    js_FramePCToLineNumber(cx, f.fp()));
 #endif
     }
 };
 
+#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
@@ -303,17 +303,17 @@ class SetPropCompiler : public PICStubCo
         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().getStubShapeJump();
+            shapeGuardJumpOffset = pic.setPropLabels().getStubShapeJumpOffset();
         else
             shapeGuardJumpOffset = pic.shapeGuard + inlineShapeJump();
         repatcher.relink(label.jumpAtOffset(shapeGuardJumpOffset), cs);
         if (lastStubSecondShapeGuard)
             repatcher.relink(label.jumpAtOffset(lastStubSecondShapeGuard), cs);
     }
 
     LookupStatus generateStub(uint32 initialShape, const Shape *shape, bool adding, bool inlineSlot)
@@ -666,16 +666,17 @@ class SetPropCompiler : public PICStubCo
             shape->hasDefaultSetter() &&
             !obj->isDenseArray()) {
             return patchInline(shape, !obj->hasSlotsArray());
         } 
 
         return generateStub(obj->shape(), shape, false, !obj->hasSlotsArray());
     }
 };
+#endif
 
 static bool
 IsCacheableProtoChain(JSObject *obj, JSObject *holder)
 {
     while (obj != holder) {
         JSObject *proto = obj->getProto();
         if (!proto->isNative())
             return false;
@@ -750,72 +751,53 @@ struct GetPropertyHelper {
     LookupStatus lookupAndTest() {
         LookupStatus status = lookup();
         if (status != Lookup_Cacheable)
             return status;
         return testForGet();
     }
 };
 
+#if defined JS_POLYIC_GETPROP
 class GetPropCompiler : public PICStubCompiler
 {
     JSObject    *obj;
     JSAtom      *atom;
     int         lastStubSecondShapeGuard;
 
-    static int32 inlineShapeOffset(ic::PICInfo &pic) {
-        return pic.getPropLabels().getInlineShapeOffset();
-    }
-
-    inline int32 inlineShapeOffset() {
-        return inlineShapeOffset(pic);
-    }
-
-    static int32 inlineShapeJump(ic::PICInfo &pic) {
-#if defined JS_NUNBOX32
-        return GETPROP_INLINE_SHAPE_JUMP;
-#elif defined JS_PUNBOX64
-        return inlineShapeOffset(pic) + GETPROP_INLINE_SHAPE_JUMP;
-#endif
-    }
-
-    inline int32 inlineShapeJump() {
-        return inlineShapeJump(pic);
-    }
-
-    static int32 dslotsLoad(ic::PICInfo &pic) {
-        return pic.getPropLabels().getDslotsLoadOffset();
-    }
-
-    inline int32 dslotsLoad() {
-        return dslotsLoad(pic);
-    }
-
   public:
     GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
                     VoidStubPIC stub)
       : 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
+    }
+
     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
     {
-        repatcher.repatchLEAToLoadPtr(pic.fastPathRejoin.instructionAtOffset(dslotsLoad(pic)));
-        repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(
-                           pic.shapeGuard + inlineShapeOffset(pic)),
+        GetPropLabels &labels = pic.getPropLabels();
+        repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin));
+        repatcher.repatch(labels.getInlineShapeData(pic.getFastShapeGuard()),
                           int32(JSObjectMap::INVALID_SHAPE));
-        repatcher.relink(pic.fastPathStart.jumpAtOffset(pic.shapeGuard + inlineShapeJump(pic)),
-                         pic.slowPathStart);
+        repatcher.relink(labels.getInlineShapeJump(pic.getFastShapeGuard()), pic.slowPathStart);
 
         if (pic.hasTypeCheck()) {
-            repatcher.relink(pic.fastPathStart.jumpAtOffset(GETPROP_INLINE_TYPE_GUARD),
-                             pic.slowPathStart.labelAtOffset(pic.u.get.typeCheckOffset));
+            /* TODO: combine pic.u.get into ICLabels? */
+            repatcher.relink(labels.getInlineTypeJump(pic.fastPathStart), pic.getSlowTypeCheck());
         }
 
         VoidStubPIC stub;
         switch (pic.kind) {
           case ic::PICInfo::GET:
             stub = ic::GetProp;
             break;
           case ic::PICInfo::CALL:
@@ -996,28 +978,28 @@ class GetPropCompiler : public PICStubCo
         if (!buffer.init(cx))
             return error();
 
         if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) ||
             !buffer.verifyRange(f.jit())) {
             return disable("code memory is out of range");
         }
 
-        buffer.link(notString, pic.slowPathStart.labelAtOffset(pic.u.get.typeCheckOffset));
+        buffer.link(notString, pic.getSlowTypeCheck());
         buffer.link(shapeMismatch, pic.slowPathStart);
         buffer.link(done, pic.fastPathRejoin);
 
         CodeLocationLabel cs = buffer.finalize();
         JaegerSpew(JSpew_PICs, "generate string call stub at %p\n",
                    cs.executableAddress());
 
         /* Patch the type check to jump here. */
         if (pic.hasTypeCheck()) {
             Repatcher repatcher(f.jit());
-            repatcher.relink(pic.fastPathStart.jumpAtOffset(GETPROP_INLINE_TYPE_GUARD), cs);
+            repatcher.relink(pic.getPropLabels().getInlineTypeJump(pic.fastPathStart), cs);
         }
 
         /* Disable the PIC so we don't keep generating stubs on the above shape mismatch. */
         disable("generated string call stub");
 
         return Lookup_Cacheable;
     }
 
@@ -1038,42 +1020,42 @@ class GetPropCompiler : public PICStubCo
         if (!buffer.init(cx))
             return error();
 
         if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) ||
             !buffer.verifyRange(f.jit())) {
             return disable("code memory is out of range");
         }
 
-        buffer.link(notString, pic.slowPathStart.labelAtOffset(pic.u.get.typeCheckOffset));
+        buffer.link(notString, pic.getSlowTypeCheck());
         buffer.link(done, pic.fastPathRejoin);
 
         CodeLocationLabel start = buffer.finalize();
         JaegerSpew(JSpew_PICs, "generate string length stub at %p\n",
                    start.executableAddress());
 
         if (pic.hasTypeCheck()) {
             Repatcher repatcher(f.jit());
-            repatcher.relink(pic.fastPathStart.jumpAtOffset(GETPROP_INLINE_TYPE_GUARD), start);
+            repatcher.relink(pic.getPropLabels().getInlineTypeJump(pic.fastPathStart), start);
         }
 
         disable("generated string length stub");
 
         return Lookup_Cacheable;
     }
 
     LookupStatus patchInline(JSObject *holder, const Shape *shape)
     {
         spew("patch", "inline");
         Repatcher repatcher(f.jit());
+        GetPropLabels &labels = pic.getPropLabels();
 
         int32 offset;
         if (!holder->hasSlotsArray()) {
-            JSC::CodeLocationInstruction istr;
-            istr = pic.fastPathRejoin.instructionAtOffset(dslotsLoad());
+            CodeLocationInstruction istr = labels.getDslotsLoad(pic.fastPathRejoin);
             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.
@@ -1081,67 +1063,60 @@ class GetPropCompiler : 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());
-        GetPropLabels &labels = pic.getPropLabels();
-#if defined JS_NUNBOX32
-        repatcher.repatch(labels.getTypeLoad(pic.fastPathRejoin), offset + 4);
-        repatcher.repatch(labels.getDataLoad(pic.fastPathRejoin), offset);
-#elif defined JS_PUNBOX64
-        repatcher.repatch(labels.getValueLoad(pic.fastPathRejoin), offset);
-#endif
+        repatcher.repatch(labels.getInlineShapeData(pic.getFastShapeGuard()), obj->shape());
+        repatcher.patchAddressOffsetForValueLoad(labels.getValueLoad(pic.fastPathRejoin), offset);
 
         pic.inlinePathPatched = true;
 
         return Lookup_Cacheable;
     }
 
     LookupStatus generateStub(JSObject *holder, const Shape *shape)
     {
         Vector<Jump, 8> shapeMismatches(cx);
 
         Assembler masm;
 
         Label start;
-        Jump shapeGuard;
+        Jump shapeGuardJump;
+        DataLabel32 shapeGuardData;
         Jump argsLenGuard;
 
         bool setStubShapeOffset = true;
         if (obj->isDenseArray()) {
             start = masm.label();
-            shapeGuard = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass());
+            shapeGuardJump = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass());
 
             /* 
              * No need to assert validity of GETPROP_STUB_SHAPE_JUMP in this case:
              * the IC is disabled after a dense array hit, so no patching can occur.
              */
 #ifndef JS_HAS_IC_LABELS
             setStubShapeOffset = false;
 #endif
         } else {
             if (pic.shapeNeedsRemat()) {
                 masm.loadShape(pic.objReg, pic.shapeReg);
                 pic.shapeRegHasBaseShape = true;
             }
 
             start = masm.label();
-            shapeGuard = masm.branch32_force32(Assembler::NotEqual, pic.shapeReg,
-                                               Imm32(obj->shape()));
+            shapeGuardJump = masm.branch32WithPatch(Assembler::NotEqual, pic.shapeReg,
+                                                    Imm32(obj->shape()), shapeGuardData);
         }
-
         Label stubShapeJumpLabel = masm.label();
 
-        if (!shapeMismatches.append(shapeGuard))
+        if (!shapeMismatches.append(shapeGuardJump))
             return error();
 
         RegisterID holderReg = pic.objReg;
         if (obj != holder) {
             // Bake in the holder identity. Careful not to clobber |objReg|, since we can't remat it.
             holderReg = pic.shapeReg;
             masm.move(ImmPtr(holder), holderReg);
             pic.shapeRegHasBaseShape = false;
@@ -1199,22 +1174,22 @@ class GetPropCompiler : public PICStubCo
         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.getPropLabels().getStubShapeJump();
+            shapeGuardJumpOffset = pic.getPropLabels().getStubShapeJumpOffset();
         else
-            shapeGuardJumpOffset = pic.shapeGuard + inlineShapeJump();
+            shapeGuardJumpOffset = pic.shapeGuard + pic.getPropLabels().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 update()
     {
         JS_ASSERT(pic.hit);
 
         GetPropertyHelper<GetPropCompiler> getprop(cx, obj, atom, *this);
         LookupStatus status = getprop.lookupAndTest();
@@ -1222,17 +1197,19 @@ class GetPropCompiler : public PICStubCo
             return status;
 
         if (obj == getprop.holder && !pic.inlinePathPatched)
             return patchInline(getprop.holder, getprop.shape);
         
         return generateStub(getprop.holder, getprop.shape);
     }
 };
-
+#endif
+
+#if defined JS_POLYIC_NAME
 class ScopeNameCompiler : public PICStubCompiler
 {
     JSObject *scopeChain;
     JSAtom *atom;
 
     GetPropertyHelper<ScopeNameCompiler> getprop;
 
     ScopeNameCompiler *thisFromCtor() { return this; }
@@ -1538,17 +1515,19 @@ class ScopeNameCompiler : public PICStub
         JSObject *normalized = obj;
         if (obj->getClass() == &js_WithClass && !shape->hasDefaultGetter())
             normalized = js_UnwrapWithObject(cx, obj);
         NATIVE_GET(cx, normalized, holder, shape, JSGET_METHOD_BARRIER, vp, return false);
 
         return true;
     }
 };
-
+#endif
+ 
+#if defined JS_POLYIC_BIND
 class BindNameCompiler : public PICStubCompiler
 {
     JSObject *scopeChain;
     JSAtom *atom;
 
     static int32 inlineJumpOffset(ic::PICInfo &pic) {
         return pic.bindNameLabels().getInlineJumpOffset();
     }
@@ -1663,17 +1642,19 @@ class BindNameCompiler : public PICStubC
 
         LookupStatus status = generateStub(obj);
         if (status == Lookup_Error)
             return NULL;
 
         return obj;
     }
 };
-
+#endif
+
+#if defined JS_POLYIC_GETPROP
 static void JS_FASTCALL
 DisabledLengthIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::Length(f);
 }
 
 static void JS_FASTCALL
 DisabledGetPropIC(VMFrame &f, ic::PICInfo *pic)
@@ -1745,17 +1726,19 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
         }
     }
 
     Value v;
     if (!obj->getProperty(f.cx, ATOM_TO_JSID(atom), &v))
         THROW();
     f.regs.sp[-1] = v;
 }
-
+#endif
+
+#if defined JS_POLYIC_SETPROP
 template <JSBool strict>
 static void JS_FASTCALL
 DisabledSetPropIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::SetName<strict>(f, pic->atom);
 }
 
 template <JSBool strict>
@@ -1792,17 +1775,19 @@ ic::SetProp(VMFrame &f, ic::PICInfo *pic
         LookupStatus status = cc.update();
         if (status == Lookup_Error)
             THROW();
     }
     
     Value rval = f.regs.sp[-1];
     stub(f, pic);
 }
-
+#endif
+
+#if defined JS_POLYIC_GETPROP
 static void JS_FASTCALL
 DisabledCallPropIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::CallProp(f, pic->atom);
 }
 
 void JS_FASTCALL
 ic::CallProp(VMFrame &f, ic::PICInfo *pic)
@@ -1909,17 +1894,19 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pi
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) {
         regs.sp[-2].setString(ATOM_TO_STRING(pic->atom));
         if (!js_OnUnknownMethod(cx, regs.sp - 2))
             THROW();
     }
 #endif
 }
-
+#endif
+
+#if defined JS_POLYIC_NAME
 static void JS_FASTCALL
 DisabledNameIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::Name(f);
 }
 
 static void JS_FASTCALL
 DisabledXNameIC(VMFrame &f, ic::PICInfo *pic)
@@ -1958,17 +1945,19 @@ ic::Name(VMFrame &f, ic::PICInfo *pic)
     if (status == Lookup_Error)
         THROW();
 
     Value rval;
     if (!cc.retrieve(&rval))
         THROW();
     f.regs.sp[0] = rval;
 }
-
+#endif
+
+#if defined JS_POLYIC_BIND
 static void JS_FASTCALL
 DisabledBindNameIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::BindName(f);
 }
 
 static void JS_FASTCALL
 DisabledBindNameICNoCache(VMFrame &f, ic::PICInfo *pic)
@@ -1989,16 +1978,17 @@ ic::BindName(VMFrame &f, ic::PICInfo *pi
     JSObject *obj = cc.update();
     if (!obj) {
         cc.disable("error");
         THROW();
     }
 
     f.regs.sp[0].setObject(*obj);
 }
+#endif
 
 bool
 BaseIC::isCallOp()
 {
     return !!(js_CodeSpec[op].format & JOF_CALLOP);
 }
 
 void
@@ -2027,16 +2017,17 @@ BaseIC::shouldUpdate(JSContext *cx)
         hit = true;
         spew(cx, "ignored", "first hit");
         return false;
     }
     JS_ASSERT(stubsGenerated < MAX_PIC_STUBS);
     return true;
 }
 
+#if defined JS_POLYIC_ELEM
 static void JS_FASTCALL
 DisabledGetElem(VMFrame &f, ic::GetElementIC *ic)
 {
     stubs::GetElem(f);
 }
 
 static void JS_FASTCALL
 DisabledCallElem(VMFrame &f, ic::GetElementIC *ic)
@@ -2734,54 +2725,65 @@ ic::SetElement(VMFrame &f, ic::SetElemen
             THROW();
     }
 
     stubs::SetElem<strict>(f);
 }
 
 template void JS_FASTCALL ic::SetElement<true>(VMFrame &f, SetElementIC *ic);
 template void JS_FASTCALL ic::SetElement<false>(VMFrame &f, SetElementIC *ic);
+#endif /* JS_POLYIC_ELEM */
 
 void
 JITScript::purgePICs()
 {
     if (!nPICs && !nGetElems && !nSetElems)
         return;
 
     Repatcher repatcher(this);
 
     for (uint32 i = 0; i < nPICs; i++) {
         ic::PICInfo &pic = pics[i];
         switch (pic.kind) {
+#ifdef JS_POLYIC_SETPROP
           case ic::PICInfo::SET:
           case ic::PICInfo::SETMETHOD:
             SetPropCompiler::reset(repatcher, pic);
             break;
+#endif
+#ifdef JS_POLYIC_NAME
           case ic::PICInfo::NAME:
           case ic::PICInfo::XNAME:
             ScopeNameCompiler::reset(repatcher, pic);
             break;
+#endif
+#ifdef JS_POLYIC_BIND
           case ic::PICInfo::BIND:
             BindNameCompiler::reset(repatcher, pic);
             break;
+#endif
+#ifdef JS_POLYIC_GETPROP
           case ic::PICInfo::CALL: /* fall-through */
           case ic::PICInfo::GET:
             GetPropCompiler::reset(repatcher, pic);
             break;
+#endif
           default:
             JS_NOT_REACHED("Unhandled PIC kind");
             break;
         }
         pic.reset();
     }
 
+#if defined JS_POLYIC_ELEM
     for (uint32 i = 0; i < nGetElems; i++)
         getElems[i].purge(repatcher);
     for (uint32 i = 0; i < nSetElems; i++)
         setElems[i].purge(repatcher);
+#endif
 }
 
 void
 ic::PurgePICs(JSContext *cx, JSScript *script)
 {
     if (script->jitNormal)
         script->jitNormal->purgePICs();
     if (script->jitCtor)
--- a/js/src/methodjit/PolyIC.h
+++ b/js/src/methodjit/PolyIC.h
@@ -73,25 +73,16 @@ static const int32 SETPROP_INLINE_STORE_
 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
 
-/* GetPropCompiler */
-#if defined JS_CPU_X86
-static const int32 GETPROP_INLINE_TYPE_GUARD   =  12; //asserted
-static const int32 GETPROP_INLINE_SHAPE_JUMP   =  12; //asserted
-#elif defined JS_CPU_X64
-static const int32 GETPROP_INLINE_TYPE_GUARD   =  19; //asserted
-static const int32 GETPROP_INLINE_SHAPE_JUMP   =   6; //asserted
-#endif
-
 /* ScopeNameCompiler */
 #if defined JS_CPU_X86
 static const int32 SCOPENAME_JUMP_OFFSET = 5; //asserted
 #elif defined JS_CPU_X64
 static const int32 SCOPENAME_JUMP_OFFSET = 5; //asserted
 #endif
 
 /* BindNameCompiler */
@@ -445,16 +436,25 @@ struct PICInfo : public BasePolyIC {
     // Return the start address of the last path in this PIC, which is the
     // inline path if no stubs have been generated yet.
     CodeLocationLabel lastPathStart() {
         if (!stubsGenerated)
             return fastPathStart;
         return CodeLocationLabel(lastStubStart.start());
     }
 
+    CodeLocationLabel getFastShapeGuard() {
+        return fastPathStart.labelAtOffset(shapeGuard);
+    }
+
+    CodeLocationLabel getSlowTypeCheck() {
+        JS_ASSERT(isGet());
+        return slowPathStart.labelAtOffset(u.get.typeCheckOffset);
+    }
+
     // Return a JITCode block corresponding to the code memory to attach a
     // new stub to.
     JITCode lastCodeBlock(JITScript *jit) {
         if (!stubsGenerated)
             return JITCode(jit->code.m_code.executableAddress(), jit->code.m_size);
         return lastStubStart;
     }