[JAEGER] Enable MICs for ARM. [Bug 588020] [r=dvander]
authorJacob Bramley <Jacob.Bramley@arm.com>
Wed, 18 Aug 2010 10:38:50 +0100
changeset 53451 c74a3e0705bf94089da7c99da12f1f4303fa6d87
parent 53450 43e1eedfc1ccc6bdea17a6e92773607eb84c8473
child 53452 9c85862fffbdbf4a077a32faaa9f2aa175d9b41a
push idunknown
push userunknown
push dateunknown
reviewersdvander
bugs588020
milestone2.0b4pre
[JAEGER] Enable MICs for ARM. [Bug 588020] [r=dvander]
js/src/assembler/assembler/MacroAssemblerARM.h
js/src/configure.in
js/src/methodjit/Compiler.cpp
js/src/methodjit/MachineRegs.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/MonoIC.h
js/src/methodjit/NunboxAssembler.h
--- a/js/src/assembler/assembler/MacroAssemblerARM.h
+++ b/js/src/assembler/assembler/MacroAssemblerARM.h
@@ -278,16 +278,26 @@ public:
     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
     {
         DataLabel32 dataLabel(this);
         m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
         m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0);
         return dataLabel;
     }
 
+    DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID hi, RegisterID lo)
+    {
+        DataLabel32 dataLabel(this);
+        m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
+        m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
+        m_assembler.dtr_u(true, lo, ARMRegisters::S0, 0);
+        m_assembler.dtr_u(true, hi, ARMRegisters::S0, 4);
+        return dataLabel;
+    }
+
     Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
     {
         Label label(this);
         load32(address, dest);
         return label;
     }
 
     void load16(BaseIndex address, RegisterID dest)
@@ -307,16 +317,37 @@ public:
     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
     {
         DataLabel32 dataLabel(this);
         m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
         m_assembler.dtr_ur(false, src, address.base, ARMRegisters::S0);
         return dataLabel;
     }
 
+    DataLabel32 store64WithAddressOffsetPatch(RegisterID hi, RegisterID lo, Address address)
+    {
+        DataLabel32 dataLabel(this);
+        m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
+        m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
+        m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0);
+        m_assembler.dtr_u(false, hi, ARMRegisters::S0, 4);
+        return dataLabel;
+    }
+
+    DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, RegisterID lo, Address address)
+    {
+        DataLabel32 dataLabel(this);
+        m_assembler.ldr_un_imm(ARMRegisters::S0, 0);
+        m_assembler.getImm(hi.m_value, ARMRegisters::S1);
+        m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base);
+        m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0);
+        m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 4);
+        return dataLabel;
+    }
+
     void store32(RegisterID src, ImplicitAddress address)
     {
         m_assembler.dataTransfer32(false, src, address.base, address.offset);
     }
 
     void store32(RegisterID src, BaseIndex address)
     {
         m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
@@ -432,16 +463,23 @@ 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));
     }
 
+    // As branch32, but allow the value ('right') to be patched.
+    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
+    {
+        dataLabel = moveWithPatch(right, ARMRegisters::S1);
+        return branch32(cond, left, ARMRegisters::S1, true);
+    }
+
     Jump branch32(Condition cond, RegisterID left, Address right)
     {
         load32(right, ARMRegisters::S1);
         return branch32(cond, left, ARMRegisters::S1);
     }
 
     Jump branch32(Condition cond, Address left, RegisterID right)
     {
@@ -817,16 +855,23 @@ public:
 
     DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         DataLabelPtr dataLabel(this);
         m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value));
         return dataLabel;
     }
 
+    DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
+    {
+        DataLabel32 dataLabel(this);
+        m_assembler.ldr_un_imm(dest, initialValue.m_value);
+        return dataLabel;
+    }
+
     Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
     {
         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1);
         Jump jump = branch32(cond, left, ARMRegisters::S1, true);
         return jump;
     }
 
     Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2589,16 +2589,17 @@ x86_64*-*)
     ENABLE_POLYIC=1
     AC_DEFINE(JS_CPU_X64)
     AC_DEFINE(JS_PUNBOX64)
     ;;
 arm*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=ARM
     ENABLE_METHODJIT=1
+    ENABLE_MONOIC=1
     AC_DEFINE(JS_CPU_ARM)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 sparc*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=Sparc
     AC_DEFINE(JS_CPU_SPARC)
     ;;
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -3499,18 +3499,23 @@ mjit::Compiler::jsop_getgname(uint32 ind
 
     /* Allocate any register other than objReg. */
     RegisterID dreg = frame.allocReg();
     /* After dreg is loaded, it's safe to clobber objReg. */
     RegisterID treg = objReg;
 
     mic.load = masm.label();
 # if defined JS_NUNBOX32
+#  if defined JS_CPU_ARM
+    DataLabel32 offsetAddress = masm.load64WithAddressOffsetPatch(address, treg, dreg);
+    JS_ASSERT(masm.differenceBetween(mic.load, offsetAddress) == 0);
+#  else
     masm.loadPayload(address, dreg);
     masm.loadTypeTag(address, treg);
+#  endif
 # elif defined JS_PUNBOX64
     Label inlineValueLoadLabel =
         masm.loadValueAsComponents(address, treg, dreg);
     mic.patchValueOffset = masm.differenceBetween(mic.load, inlineValueLoadLabel);
     JS_ASSERT(mic.patchValueOffset == masm.differenceBetween(mic.load, inlineValueLoadLabel));
 # endif
 
     frame.pushRegs(treg, dreg);
@@ -3596,30 +3601,47 @@ mjit::Compiler::jsop_setgname(uint32 ind
         if (!mic.u.name.typeConst)
             typeReg = frame.ownRegForType(fe);
         else
             typeTag = fe->getKnownType();
     } else {
         v = fe->getValue();
     }
 
-    mic.load = masm.label();
     masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
     Address address(objReg, slot);
 
+    mic.load = masm.label();
+
 #if defined JS_NUNBOX32
+# if defined JS_CPU_ARM
+    DataLabel32 offsetAddress;
+    if (mic.u.name.dataConst) {
+        offsetAddress = masm.moveWithPatch(Imm32(address.offset), JSC::ARMRegisters::S0);
+        masm.add32(address.base, JSC::ARMRegisters::S0);
+        masm.storeValue(v, Address(JSC::ARMRegisters::S0, 0));
+    } else {
+        if (mic.u.name.typeConst) {
+            offsetAddress = masm.store64WithAddressOffsetPatch(ImmType(typeTag), dataReg, address);
+        } else {
+            offsetAddress = masm.store64WithAddressOffsetPatch(typeReg, dataReg, address);
+        }
+    }
+    JS_ASSERT(masm.differenceBetween(mic.load, offsetAddress) == 0);
+# else
     if (mic.u.name.dataConst) {
         masm.storeValue(v, address);
     } else {
         if (mic.u.name.typeConst)
             masm.storeTypeTag(ImmType(typeTag), address);
         else
             masm.storeTypeTag(typeReg, address);
         masm.storePayload(dataReg, address);
     }
+# endif
 #elif defined JS_PUNBOX64
     if (mic.u.name.dataConst) {
         /* Emits a single move. No code length variation. */
         masm.storeValue(v, address);
     } else {
         if (mic.u.name.typeConst)
             masm.move(ImmType(typeTag), Registers::ValueReg);
         else
--- a/js/src/methodjit/MachineRegs.h
+++ b/js/src/methodjit/MachineRegs.h
@@ -125,24 +125,31 @@ struct Registers {
           (1 << JSC::X86Registers::ebp) |
           (1 << JSC::X86Registers::esp));
 
 #elif defined(JS_CPU_ARM)
     static const uint32 TempRegs =
           (1 << JSC::ARMRegisters::r0)
         | (1 << JSC::ARMRegisters::r1)
         | (1 << JSC::ARMRegisters::r2);
+    // r3 is reserved as a scratch register for the assembler.
 
     static const uint32 SavedRegs =
           (1 << JSC::ARMRegisters::r4)
         | (1 << JSC::ARMRegisters::r5)
         | (1 << JSC::ARMRegisters::r6)
         | (1 << JSC::ARMRegisters::r7)
+    // r8 is reserved as a scratch register for the assembler.
         | (1 << JSC::ARMRegisters::r9)
         | (1 << JSC::ARMRegisters::r10);
+    // r11 is reserved for JSFrameReg.
+    // r12 is IP, and is used for stub calls.
+    // r13 is SP and must always point to VMFrame whilst in generated code.
+    // r14 is LR and is used for return sequences.
+    // r15 is PC (program counter).
 
     static const uint32 SingleByteRegs = TempRegs | SavedRegs;
 #else
 # error "Unsupported platform"
 #endif
 
     static const uint32 AvailRegs = SavedRegs | TempRegs;
 
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -96,19 +96,23 @@ ic::GetGlobalName(VMFrame &f, uint32 ind
     JSC::RepatchBuffer repatch(mic.entry.executableAddress(), 50);
     repatch.repatch(mic.shape, shape);
 
     /* Patch loads. */
     JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
     slot -= JS_INITIAL_NSLOTS;
     slot *= sizeof(Value);
     JSC::RepatchBuffer loads(mic.load.executableAddress(), 32, false);
-#if defined JS_NUNBOX32
+#if defined JS_CPU_X86
     loads.repatch(mic.load.dataLabel32AtOffset(MICInfo::GET_DATA_OFFSET), slot);
     loads.repatch(mic.load.dataLabel32AtOffset(MICInfo::GET_TYPE_OFFSET), slot + 4);
+#elif defined JS_CPU_ARM
+    // mic.load actually points to the LDR instruction which fetches the offset, but 'repatch'
+    // knows how to dereference it to find the integer value.
+    loads.repatch(mic.load.dataLabel32AtOffset(0), slot);
 #elif defined JS_PUNBOX64
     loads.repatch(mic.load.dataLabel32AtOffset(mic.patchValueOffset), slot);
 #endif
 
     /* Do load anyway... this time. */
     stubs::GetGlobalName(f);
 }
 
@@ -162,26 +166,30 @@ ic::SetGlobalName(VMFrame &f, uint32 ind
     repatch.repatch(mic.shape, shape);
 
     /* Patch loads. */
     JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
     slot -= JS_INITIAL_NSLOTS;
     slot *= sizeof(Value);
 
     JSC::RepatchBuffer stores(mic.load.executableAddress(), 32, false);
-#if defined JS_NUNBOX32
+#if defined JS_CPU_X86
     stores.repatch(mic.load.dataLabel32AtOffset(MICInfo::SET_TYPE_OFFSET), slot + 4);
 
     uint32 dataOffset;
     if (mic.u.name.typeConst)
         dataOffset = MICInfo::SET_DATA_CONST_TYPE_OFFSET;
     else
         dataOffset = MICInfo::SET_DATA_TYPE_OFFSET;
     if (mic.u.name.dataWrite)
         stores.repatch(mic.load.dataLabel32AtOffset(dataOffset), slot);
+#elif defined JS_CPU_ARM
+    // mic.load actually points to the LDR instruction which fetches the offset, but 'repatch'
+    // knows how to dereference it to find the integer value.
+    stores.repatch(mic.load.dataLabel32AtOffset(0), slot);
 #elif defined JS_PUNBOX64
     stores.repatch(mic.load.dataLabel32AtOffset(mic.patchValueOffset), slot);
 #endif
 
     /* Do load anyway... this time. */
     stubs::SetGlobalName(f, atom);
 }
 
--- a/js/src/methodjit/MonoIC.h
+++ b/js/src/methodjit/MonoIC.h
@@ -50,21 +50,22 @@ namespace js {
 namespace mjit {
 namespace ic {
 
 struct MICInfo {
 #ifdef JS_CPU_X86
     static const uint32 GET_DATA_OFFSET = 6;
     static const uint32 GET_TYPE_OFFSET = 12;
 
-    static const uint32 SET_TYPE_OFFSET = 9;
-    static const uint32 SET_DATA_CONST_TYPE_OFFSET = 19;
-    static const uint32 SET_DATA_TYPE_OFFSET = 15;
-#elif JS_CPU_X64
-    /* No constants used, thanks to patchValueOffset. */
+    static const uint32 SET_TYPE_OFFSET = 6;
+    static const uint32 SET_DATA_CONST_TYPE_OFFSET = 16;
+    static const uint32 SET_DATA_TYPE_OFFSET = 12;
+#elif JS_CPU_X64 || JS_CPU_ARM
+    /* X64: No constants used, thanks to patchValueOffset. */
+    /* ARM: No constants used as mic.load always points to an LDR that loads the offset. */
 #endif
 
     enum Kind
 #ifdef _MSC_VER
     : uint8_t
 #endif
     {
         GET,
--- a/js/src/methodjit/NunboxAssembler.h
+++ b/js/src/methodjit/NunboxAssembler.h
@@ -148,17 +148,16 @@ class Assembler : public BaseAssembler
     }
 
     void storePayload(Imm32 imm, Address address) {
         store32(imm, payloadOf(address));
     }
 
     /*
      * Stores type first, then payload.
-     * Returns label after type store. Useful for offset verification.
      */
     void storeValue(const Value &v, Address address) {
         jsval_layout jv;
         jv.asBits = JSVAL_BITS(Jsvalify(v));
 
         store32(ImmTag(jv.s.tag), tagOf(address));
         if (!v.isUndefined())
             store32(Imm32(jv.s.payload.u32), payloadOf(address));