Bug 588021: Port ELEM PICs for ARM. (r=dmandelin)
authorChris Leary <cdleary@mozilla.com>
Thu, 13 Jan 2011 22:42:28 -0800
changeset 60597 a08bbc16b665b9c755ad0aab242aea4558855a6f
parent 60596 d3ca3ea64e570e0bd7c1d230e996b0857b431a99
child 60598 a5d0ccdb9985e5fdb052541bb4a8cfda28da291c
push idunknown
push userunknown
push dateunknown
reviewersdmandelin
bugs588021
milestone2.0b10pre
Bug 588021: Port ELEM PICs for ARM. (r=dmandelin)
js/src/assembler/assembler/MacroAssemblerARM.h
js/src/configure.in
js/src/methodjit/BaseCompiler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/PolyIC.cpp
--- a/js/src/assembler/assembler/MacroAssemblerARM.h
+++ b/js/src/assembler/assembler/MacroAssemblerARM.h
@@ -491,16 +491,21 @@ public:
         if (right.m_isPointer) {
             m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value);
             m_assembler.cmp_r(left, ARMRegisters::S0);
         } else
             m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
     }
 
+    Jump branch32_force32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0)
+    {
+        return branch32(cond, left, right, useConstantPool);
+    }
+
     // As branch32, but allow the value ('right') to be patched.
     Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left != ARMRegisters::S1);
         dataLabel = moveWithPatch(right, ARMRegisters::S1);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2913,44 +2913,50 @@ i?86-*)
     ENABLE_METHODJIT=1
     ENABLE_MONOIC=1
     ENABLE_POLYIC=1
     ENABLE_POLYIC_GETPROP=1
     ENABLE_POLYIC_SETPROP=1
     ENABLE_POLYIC_CALLPROP=1
     ENABLE_POLYIC_BIND=1
     ENABLE_POLYIC_NAME=1
+    ENABLE_POLYIC_GETELEM=1
+    ENABLE_POLYIC_SETELEM=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_CALLPROP=1
     ENABLE_POLYIC_BIND=1
     ENABLE_POLYIC_NAME=1
+    ENABLE_POLYIC_GETELEM=1
+    ENABLE_POLYIC_SETELEM=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_CALLPROP=1
     ENABLE_POLYIC_BIND=1
     ENABLE_POLYIC_NAME=1
+    ENABLE_POLYIC_GETELEM=1
+    ENABLE_POLYIC_SETELEM=1
     AC_DEFINE(JS_CPU_ARM)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 sparc*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=Sparc
     AC_DEFINE(JS_CPU_SPARC)
     ;;
@@ -3006,18 +3012,22 @@ fi
 if test "$ENABLE_POLYIC_NAME"; then
     AC_DEFINE(JS_POLYIC_NAME)
 fi
 
 if test "$ENABLE_POLYIC_BIND"; then
     AC_DEFINE(JS_POLYIC_BIND)
 fi
 
-if test "$ENABLE_POLYIC_ELEM"; then
-    AC_DEFINE(JS_POLYIC_ELEM)
+if test "$ENABLE_POLYIC_GETELEM"; then
+    AC_DEFINE(JS_POLYIC_GETELEM)
+fi
+
+if test "$ENABLE_POLYIC_SETELEM"; then
+    AC_DEFINE(JS_POLYIC_SETELEM)
 fi
 
 if test "$ENABLE_METHODJIT_SPEW"; then
     AC_DEFINE(JS_METHODJIT_SPEW)
 fi
 
 if test "$ENABLE_TRACEJIT"; then
 
--- a/js/src/methodjit/BaseCompiler.h
+++ b/js/src/methodjit/BaseCompiler.h
@@ -261,17 +261,17 @@ class AutoReserveICSpace {
         /* Automatically check the IC space if we didn't already do it manually. */
         if (!didCheck) {
             check();
         }
 #endif
     }
 };
 
-# define RESERVE_IC_SPACE(__masm)       AutoReserveICSpace<80> arics(__masm)
+# define RESERVE_IC_SPACE(__masm)       AutoReserveICSpace<96> 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. */
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -43,16 +43,17 @@
 #include "jsnum.h"
 #include "jsbool.h"
 #include "jsemit.h"
 #include "jsiter.h"
 #include "Compiler.h"
 #include "StubCalls.h"
 #include "MonoIC.h"
 #include "PolyIC.h"
+#include "ICChecker.h"
 #include "Retcon.h"
 #include "assembler/jit/ExecutableAllocator.h"
 #include "assembler/assembler/LinkBuffer.h"
 #include "FrameState-inl.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 #include "InlineFrameAssembler.h"
 #include "jscompartment.h"
@@ -637,17 +638,17 @@ mjit::Compiler::finishThisUp(JITScript *
         CallPatchInfo &patch = callPatches[i];
 
         if (patch.hasFastNcode)
             fullCode.patch(patch.fastNcodePatch, fullCode.locationOf(patch.joinPoint));
         if (patch.hasSlowNcode)
             stubCode.patch(patch.slowNcodePatch, fullCode.locationOf(patch.joinPoint));
     }
 
-#if defined JS_POLYIC
+#if defined JS_POLYIC_GETELEM
     jit->nGetElems = getElemICs.length();
     if (getElemICs.length()) {
         jit->getElems = (ic::GetElementIC *)cursor;
         cursor += sizeof(ic::GetElementIC) * getElemICs.length();
     } else {
         jit->getElems = NULL;
     }
 
@@ -670,17 +671,19 @@ mjit::Compiler::finishThisUp(JITScript *
         }
         int inlineClaspGuard = fullCode.locationOf(from.claspGuard) -
                                fullCode.locationOf(from.fastPathStart);
         to.inlineClaspGuard = inlineClaspGuard;
         JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard);
 
         stubCode.patch(from.paramAddr, &to);
     }
-
+#endif /* JS_POLYIC_GETELEM */
+
+#if defined JS_POLYIC_SETELEM
     jit->nSetElems = setElemICs.length();
     if (setElemICs.length()) {
         jit->setElems = (ic::SetElementIC *)cursor;
         cursor += sizeof(ic::SetElementIC) * setElemICs.length();
     } else {
         jit->setElems = NULL;
     }
 
@@ -708,22 +711,26 @@ mjit::Compiler::finishThisUp(JITScript *
         to.inlineClaspGuard = inlineClaspGuard;
         JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard);
 
         int inlineHoleGuard = fullCode.locationOf(from.holeGuard) -
                                fullCode.locationOf(from.fastPathStart);
         to.inlineHoleGuard = inlineHoleGuard;
         JS_ASSERT(to.inlineHoleGuard == inlineHoleGuard);
 
+        CheckIsStubCall(to.slowPathCall.labelAtOffset(0));
+
         to.volatileMask = from.volatileMask;
         JS_ASSERT(to.volatileMask == from.volatileMask);
 
         stubCode.patch(from.paramAddr, &to);
     }
-
+#endif /* JS_POLYIC_SETELEM */
+
+#if defined JS_POLYIC
     jit->nPICs = pics.length();
     if (pics.length()) {
         jit->pics = (ic::PICInfo *)cursor;
         cursor += sizeof(ic::PICInfo) * pics.length();
     } else {
         jit->pics = NULL;
     }
 
@@ -749,17 +756,17 @@ mjit::Compiler::finishThisUp(JITScript *
                                      stubcc.masm.distanceOf(pics[i].slowPathStart);
                     JS_ASSERT(distance <= 0);
                     scriptPICs[i].u.get.typeCheckOffset = distance;
                 }
             }
             stubCode.patch(pics[i].paramAddr, &scriptPICs[i]);
         }
     }
-#endif /* JS_POLYIC */
+#endif
 
     /* Link fast and slow paths together. */
     stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size());
 
     /* Patch all double references. */
     size_t doubleOffset = masm.size() + stubcc.size();
     double *doubleVec = (double *)(result + doubleOffset);
     for (size_t i = 0; i < doubleList.length(); i++) {
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1251,20 +1251,22 @@ mjit::Compiler::jsop_setelem(bool popGua
     // Unpin the value since register allocation is complete.
     frame.unpinEntry(ic.vr);
 
     // Now it's also safe to grab remat info for obj (all exits that can
     // generate stubs must have the same register state).
     ic.objRemat = frame.dataRematInfo(obj);
 
     // All patchable guards must occur after this point.
+    RESERVE_IC_SPACE(masm);
     ic.fastPathStart = masm.label();
 
     // Create the common out-of-line sync block, taking care to link previous
     // guards here after.
+    RESERVE_OOL_SPACE(stubcc.masm);
     ic.slowPathStart = stubcc.syncExit(Uses(3));
 
     // Guard obj is a dense array.
     ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &js_ArrayClass);
     stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart);
 
     // Guard capacity in range.
     Jump capacityGuard = masm.guardArrayCapacity(ic.objReg, ic.key);
@@ -1422,19 +1424,21 @@ mjit::Compiler::jsop_getelem(bool isCall
     } else {
         RegisterID dataReg = frame.tempRegForData(id);
         if (id->isTypeKnown())
             ic.id = ValueRemat::FromKnownType(id->getKnownType(), dataReg);
         else
             ic.id = ValueRemat::FromRegisters(ic.typeReg, dataReg);
     }
 
+    RESERVE_IC_SPACE(masm);
     ic.fastPathStart = masm.label();
 
     // Note: slow path here is safe, since the frame will not be modified.
+    RESERVE_OOL_SPACE(stubcc.masm);
     ic.slowPathStart = stubcc.masm.label();
     frame.sync(stubcc.masm, Uses(2));
 
     if (id->mightBeType(JSVAL_TYPE_INT32)) {
         // Always test the type first (see comment in PolyIC.h).
         if (!id->isTypeKnown()) {
             ic.typeGuard = masm.testInt32(Assembler::NotEqual, ic.typeReg);
             stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart);
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -1033,17 +1033,16 @@ class GetPropCompiler : public PICStubCo
     LookupStatus generateStub(JSObject *holder, const Shape *shape)
     {
         Vector<Jump, 8> shapeMismatches(cx);
 
         Assembler masm;
 
         Label start;
         Jump shapeGuardJump;
-        DataLabel32 shapeGuardData;
         Jump argsLenGuard;
 
         bool setStubShapeOffset = true;
         if (obj->isDenseArray()) {
             start = masm.label();
             shapeGuardJump = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass());
 
             /* 
@@ -1055,18 +1054,18 @@ class GetPropCompiler : public PICStubCo
 #endif
         } else {
             if (pic.shapeNeedsRemat()) {
                 masm.loadShape(pic.objReg, pic.shapeReg);
                 pic.shapeRegHasBaseShape = true;
             }
 
             start = masm.label();
-            shapeGuardJump = masm.branch32WithPatch(Assembler::NotEqual, pic.shapeReg,
-                                                    Imm32(obj->shape()), shapeGuardData);
+            shapeGuardJump = masm.branch32_force32(Assembler::NotEqual, pic.shapeReg,
+                                                   Imm32(obj->shape()));
         }
         Label stubShapeJumpLabel = masm.label();
 
         if (!shapeMismatches.append(shapeGuardJump))
             return error();
 
         RegisterID holderReg = pic.objReg;
         if (obj != holder) {
@@ -1990,17 +1989,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
+#if defined JS_POLYIC_GETELEM
 static void JS_FASTCALL
 DisabledGetElem(VMFrame &f, ic::GetElementIC *ic)
 {
     stubs::GetElem(f);
 }
 
 static void JS_FASTCALL
 DisabledCallElem(VMFrame &f, ic::GetElementIC *ic)
@@ -2043,20 +2042,23 @@ GetElementIC::purge(Repatcher &repatcher
 {
     // Repatch the inline jumps.
     if (inlineTypeGuardPatched)
         repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), slowPathStart);
     if (inlineClaspGuardPatched)
         repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), slowPathStart);
 
     if (slowCallPatched) {
-        if (op == JSOP_GETELEM)
-            repatcher.relink(slowPathCall, FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::GetElement)));
-        else if (op == JSOP_CALLELEM)
-            repatcher.relink(slowPathCall, FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::CallElement)));
+        if (op == JSOP_GETELEM) {
+            repatcher.relink(slowPathCall,
+                             FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::GetElement)));
+        } else if (op == JSOP_CALLELEM) {
+            repatcher.relink(slowPathCall,
+                             FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::CallElement)));
+        }
     }
 
     reset();
 }
 
 LookupStatus
 GetElementIC::attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp)
 {
@@ -2439,17 +2441,19 @@ ic::GetElement(VMFrame &f, ic::GetElemen
             JS_ASSERT(!f.regs.sp[-2].isMagic());
             return;
         }
     }
 
     if (!obj->getProperty(cx, id, &f.regs.sp[-2]))
         THROW();
 }
-
+#endif /* JS_POLYIC_GETELEM */
+
+#ifdef JS_POLYIC_SETELEM
 #define APPLY_STRICTNESS(f, s)                          \
     (FunctionTemplateConditional(s, f<true>, f<false>))
 
 LookupStatus
 SetElementIC::disable(JSContext *cx, const char *reason)
 {
     slowCallPatched = true;
     VoidStub stub = APPLY_STRICTNESS(stubs::SetElem, strictMode);
@@ -2698,17 +2702,17 @@ 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 */
+#endif /* JS_POLYIC_SETELEM */
 
 void
 JITScript::purgePICs()
 {
     if (!nPICs && !nGetElems && !nSetElems)
         return;
 
     Repatcher repatcher(this);
@@ -2741,19 +2745,21 @@ JITScript::purgePICs()
 #endif
           default:
             JS_NOT_REACHED("Unhandled PIC kind");
             break;
         }
         pic.reset();
     }
 
-#if defined JS_POLYIC_ELEM
+#if defined JS_POLYIC_GETELEM
     for (uint32 i = 0; i < nGetElems; i++)
         getElems[i].purge(repatcher);
+#endif
+#if defined JS_POLYIC_SETELEM
     for (uint32 i = 0; i < nSetElems; i++)
         setElems[i].purge(repatcher);
 #endif
 }
 
 void
 ic::PurgePICs(JSContext *cx, JSScript *script)
 {