Changeset 50255 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Oct 28, 2009, 6:40:09 PM (16 years ago)
Author:
[email protected]
Message:

JSC JIT on ARMv7 cannot link jumps >16Mb range
https://bugs.webkit.org/show_bug.cgi?id=30891

Patch by Gavin Barraclough <[email protected]> on 2009-10-28
Reviewed by Oliver Hunt.

Start planing all relative jumps as move-32-bit-immediate-to-register-BX.
In the cases where the jump would fall within a relative jump range, use a relative jump.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • assembler/ARMv7Assembler.h:

(JSC::ARMv7Assembler::~ARMv7Assembler):
(JSC::ARMv7Assembler::LinkRecord::LinkRecord):
(JSC::ARMv7Assembler::):
(JSC::ARMv7Assembler::executableCopy):
(JSC::ARMv7Assembler::linkJump):
(JSC::ARMv7Assembler::relinkJump):
(JSC::ARMv7Assembler::setInt32):
(JSC::ARMv7Assembler::isB):
(JSC::ARMv7Assembler::isBX):
(JSC::ARMv7Assembler::isMOV_imm_T3):
(JSC::ARMv7Assembler::isMOVT):
(JSC::ARMv7Assembler::isNOP_T1):
(JSC::ARMv7Assembler::isNOP_T2):
(JSC::ARMv7Assembler::linkJumpAbsolute):
(JSC::ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst):
(JSC::ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond):
(JSC::ARMv7Assembler::ARMInstructionFormatter::twoWordOp5i6Imm4Reg4EncodedImm):

  • assembler/MacroAssemblerARMv7.h:

(JSC::MacroAssemblerARMv7::makeJump):
(JSC::MacroAssemblerARMv7::makeBranch):

  • jit/JIT.h:
  • wtf/Platform.h:
Location:
trunk/JavaScriptCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r50254 r50255  
     12009-10-28  Gavin Barraclough  <[email protected]>
     2
     3        Reviewed by Oliver Hunt.
     4
     5        JSC JIT on ARMv7 cannot link jumps >16Mb range
     6        https://bugs.webkit.org/show_bug.cgi?id=30891
     7
     8        Start planing all relative jumps as move-32-bit-immediate-to-register-BX.
     9        In the cases where the jump would fall within a relative jump range, use a relative jump.
     10
     11        * JavaScriptCore.xcodeproj/project.pbxproj:
     12        * assembler/ARMv7Assembler.h:
     13        (JSC::ARMv7Assembler::~ARMv7Assembler):
     14        (JSC::ARMv7Assembler::LinkRecord::LinkRecord):
     15        (JSC::ARMv7Assembler::):
     16        (JSC::ARMv7Assembler::executableCopy):
     17        (JSC::ARMv7Assembler::linkJump):
     18        (JSC::ARMv7Assembler::relinkJump):
     19        (JSC::ARMv7Assembler::setInt32):
     20        (JSC::ARMv7Assembler::isB):
     21        (JSC::ARMv7Assembler::isBX):
     22        (JSC::ARMv7Assembler::isMOV_imm_T3):
     23        (JSC::ARMv7Assembler::isMOVT):
     24        (JSC::ARMv7Assembler::isNOP_T1):
     25        (JSC::ARMv7Assembler::isNOP_T2):
     26        (JSC::ARMv7Assembler::linkJumpAbsolute):
     27        (JSC::ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst):
     28        (JSC::ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond):
     29        (JSC::ARMv7Assembler::ARMInstructionFormatter::twoWordOp5i6Imm4Reg4EncodedImm):
     30        * assembler/MacroAssemblerARMv7.h:
     31        (JSC::MacroAssemblerARMv7::makeJump):
     32        (JSC::MacroAssemblerARMv7::makeBranch):
     33        * jit/JIT.h:
     34        * wtf/Platform.h:
     35
    1362009-10-28  Oliver Hunt  <[email protected]>
    237
  • trunk/JavaScriptCore/assembler/ARMv7Assembler.h

    r48525 r50255  
    408408class ARMv7Assembler {
    409409public:
     410    ~ARMv7Assembler()
     411    {
     412        ASSERT(m_jumpsToLink.isEmpty());
     413    }
     414
    410415    typedef ARMRegisters::RegisterID RegisterID;
    411416    typedef ARMRegisters::FPRegisterID FPRegisterID;
     
    477482
    478483private:
     484
     485    struct LinkRecord {
     486        LinkRecord(intptr_t from, intptr_t to)
     487            : from(from)
     488            , to(to)
     489        {
     490        }
     491
     492        intptr_t from;
     493        intptr_t to;
     494    };
    479495
    480496    // ARMv7, Appx-A.6.3
     
    575591        OP_BKPT             = 0xBE00,
    576592        OP_IT               = 0xBF00,
     593        OP_NOP_T1           = 0xBF00,
    577594    } OpcodeID;
    578595
     
    609626        OP_SUB_imm_T4   = 0xF2A0,
    610627        OP_MOVT         = 0xF2C0,
     628        OP_NOP_T2a      = 0xF3AF,
    611629        OP_LDRH_reg_T2  = 0xF830,
    612630        OP_LDRH_imm_T3  = 0xF830,
     
    627645    typedef enum {
    628646        OP_B_T4b        = 0x9000,
     647        OP_NOP_T2b      = 0x8000,
    629648    } OpcodeID2;
    630649
     
    14821501    {
    14831502        void* copy = m_formatter.executableCopy(allocator);
     1503
     1504        unsigned jumpCount = m_jumpsToLink.size();
     1505        for (unsigned i = 0; i < jumpCount; ++i) {
     1506            uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(copy) + m_jumpsToLink[i].from);
     1507            uint16_t* target = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(copy) + m_jumpsToLink[i].to);
     1508            linkJumpAbsolute(location, target);
     1509        }
     1510        m_jumpsToLink.clear();
     1511
    14841512        ASSERT(copy);
    14851513        return copy;
     
    15041532        ASSERT(to.m_offset != -1);
    15051533        ASSERT(from.m_offset != -1);
    1506 
    1507         uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(m_formatter.data()) + from.m_offset);
    1508         intptr_t relative = to.m_offset - from.m_offset;
    1509 
    1510         linkWithOffset(location, relative);
     1534        m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset));
    15111535    }
    15121536
     
    15161540       
    15171541        uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
    1518         intptr_t relative = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(location);
    1519 
    1520         linkWithOffset(location, relative);
     1542        linkJumpAbsolute(location, to);
    15211543    }
    15221544
     
    15421564        ASSERT(!(reinterpret_cast<intptr_t>(to) & 1));
    15431565
    1544         intptr_t relative = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from);
    1545         linkWithOffset(reinterpret_cast<uint16_t*>(from), relative);
    1546 
    1547         ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 2, 2 * sizeof(uint16_t));
     1566        linkJumpAbsolute(reinterpret_cast<uint16_t*>(from), to);
     1567
     1568        ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 5 * sizeof(uint16_t));
    15481569    }
    15491570   
     
    16141635    {
    16151636        uint16_t* location = reinterpret_cast<uint16_t*>(code);
    1616 
    1617         uint16_t lo16 = value;
    1618         uint16_t hi16 = value >> 16;
    1619 
    1620         spliceHi5(location - 4, lo16);
    1621         spliceLo11(location - 3, lo16);
    1622         spliceHi5(location - 2, hi16);
    1623         spliceLo11(location - 1, hi16);
     1637        ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2));
     1638
     1639        ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value));
     1640        ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value >> 16));
     1641        location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
     1642        location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16);
     1643        location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
     1644        location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16);
    16241645
    16251646        ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t));
     
    16311652    }
    16321653
    1633     // Linking & patching:
    1634     // This method assumes that the JmpSrc being linked is a T4 b instruction.
    1635     static void linkWithOffset(uint16_t* instruction, intptr_t relative)
    1636     {
    1637         // Currently branches > 16m = mostly deathy.
    1638         if (((relative << 7) >> 7) != relative) {
    1639             // FIXME: This CRASH means we cannot turn the JIT on by default on arm-v7.
    1640             fprintf(stderr, "Error: Cannot link T4b.\n");
    1641             CRASH();
    1642         }
    1643        
    1644         // ARM encoding for the top two bits below the sign bit is 'peculiar'.
    1645         if (relative >= 0)
    1646             relative ^= 0xC00000;
    1647 
    1648         // All branch offsets should be an even distance.
    1649         ASSERT(!(relative & 1));
    1650 
    1651         int word1 = ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12);
    1652         int word2 = ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1);
    1653 
    1654         instruction[-2] = OP_B_T4a | word1;
    1655         instruction[-1] = OP_B_T4b | word2;
    1656     }
    1657 
    1658     // These functions can be used to splice 16-bit immediates back into previously generated instructions.
    1659     static void spliceHi5(uint16_t* where, uint16_t what)
    1660     {
    1661         uint16_t pattern = (what >> 12) | ((what & 0x0800) >> 1);
    1662         *where = (*where & 0xFBF0) | pattern;
    1663     }
    1664     static void spliceLo11(uint16_t* where, uint16_t what)
    1665     {
    1666         uint16_t pattern = ((what & 0x0700) << 4) | (what & 0x00FF);
    1667         *where = (*where & 0x8F00) | pattern;
     1654    static bool isB(void* address)
     1655    {
     1656        uint16_t* instruction = static_cast<uint16_t*>(address);
     1657        return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b);
     1658    }
     1659
     1660    static bool isBX(void* address)
     1661    {
     1662        uint16_t* instruction = static_cast<uint16_t*>(address);
     1663        return (instruction[0] & 0xff87) == OP_BX;
     1664    }
     1665
     1666    static bool isMOV_imm_T3(void* address)
     1667    {
     1668        uint16_t* instruction = static_cast<uint16_t*>(address);
     1669        return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0);
     1670    }
     1671
     1672    static bool isMOVT(void* address)
     1673    {
     1674        uint16_t* instruction = static_cast<uint16_t*>(address);
     1675        return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0);
     1676    }
     1677
     1678    static bool isNOP_T1(void* address)
     1679    {
     1680        uint16_t* instruction = static_cast<uint16_t*>(address);
     1681        return instruction[0] == OP_NOP_T1;
     1682    }
     1683
     1684    static bool isNOP_T2(void* address)
     1685    {
     1686        uint16_t* instruction = static_cast<uint16_t*>(address);
     1687        return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b);
     1688    }
     1689
     1690    static void linkJumpAbsolute(uint16_t* instruction, void* target)
     1691    {
     1692        // FIMXE: this should be up in the MacroAssembler layer. :-(
     1693        const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip;
     1694
     1695        ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
     1696        ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
     1697
     1698        ASSERT( (isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1))
     1699            || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)) );
     1700
     1701        intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction));
     1702        if (((relative << 7) >> 7) == relative) {
     1703            // ARM encoding for the top two bits below the sign bit is 'peculiar'.
     1704            if (relative >= 0)
     1705                relative ^= 0xC00000;
     1706
     1707            // All branch offsets should be an even distance.
     1708            ASSERT(!(relative & 1));
     1709            // There may be a better way to fix this, but right now put the NOPs first, since in the
     1710            // case of an conditional branch this will be coming after an ITTT predicating *three*
     1711            // instructions!  Looking backwards to modify the ITTT to an IT is not easy, due to
     1712            // variable wdith encoding - the previous instruction might *look* like an ITTT but
     1713            // actually be the second half of a 2-word op.
     1714            instruction[-5] = OP_NOP_T1;
     1715            instruction[-4] = OP_NOP_T2a;
     1716            instruction[-3] = OP_NOP_T2b;
     1717            instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12);
     1718            instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1);
     1719        } else {
     1720            ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1));
     1721            ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16));
     1722            instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16);
     1723            instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16);
     1724            instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
     1725            instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
     1726            instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
     1727        }
     1728    }
     1729
     1730    static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm)
     1731    {
     1732        return op | (imm.m_value.i << 10) | imm.m_value.imm4;
     1733    }
     1734    static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm)
     1735    {
     1736        return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8;
    16681737    }
    16691738
     
    17241793        void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm)
    17251794        {
    1726             m_buffer.putShort(op | (imm.m_value.i << 10) | imm4);
    1727             m_buffer.putShort((imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8);
     1795            ARMThumbImmediate newImm = imm;
     1796            newImm.m_value.imm4 = imm4;
     1797
     1798            m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm));
     1799            m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm));
    17281800        }
    17291801
     
    17501822        AssemblerBuffer m_buffer;
    17511823    } m_formatter;
     1824
     1825    Vector<LinkRecord> m_jumpsToLink;
    17521826};
    17531827
  • trunk/JavaScriptCore/assembler/MacroAssemblerARMv7.h

    r48782 r50255  
    991991    ARMv7Assembler::JmpSrc makeJump()
    992992    {
    993         return m_assembler.b();
     993        moveFixedWidthEncoding(Imm32(0), dataTempRegister);
     994        return m_assembler.bx(dataTempRegister);
    994995    }
    995996
    996997    ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond)
    997998    {
    998         m_assembler.it(cond);
    999         return m_assembler.b();
     999        m_assembler.it(cond, true, true);
     1000        moveFixedWidthEncoding(Imm32(0), dataTempRegister);
     1001        return m_assembler.bx(dataTempRegister);
    10001002    }
    10011003    ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); }
  • trunk/JavaScriptCore/jit/JIT.h

    r50254 r50255  
    587587        // These architecture specific value are used to enable patching - see comment on op_put_by_id.
    588588        static const int patchOffsetPutByIdStructure = 10;
    589         static const int patchOffsetPutByIdExternalLoad = 20;
     589        static const int patchOffsetPutByIdExternalLoad = 26;
    590590        static const int patchLengthPutByIdExternalLoad = 12;
    591         static const int patchOffsetPutByIdPropertyMapOffset = 40;
     591        static const int patchOffsetPutByIdPropertyMapOffset = 46;
    592592        // These architecture specific value are used to enable patching - see comment on op_get_by_id.
    593593        static const int patchOffsetGetByIdStructure = 10;
    594         static const int patchOffsetGetByIdBranchToSlowCase = 20;
    595         static const int patchOffsetGetByIdExternalLoad = 20;
     594        static const int patchOffsetGetByIdBranchToSlowCase = 26;
     595        static const int patchOffsetGetByIdExternalLoad = 26;
    596596        static const int patchLengthGetByIdExternalLoad = 12;
    597         static const int patchOffsetGetByIdPropertyMapOffset = 40;
    598         static const int patchOffsetGetByIdPutResult = 44;
     597        static const int patchOffsetGetByIdPropertyMapOffset = 46;
     598        static const int patchOffsetGetByIdPutResult = 50;
    599599#if ENABLE(OPCODE_SAMPLING)
    600600        static const int patchOffsetGetByIdSlowCaseCall = 0; // FIMXE
     
    602602        static const int patchOffsetGetByIdSlowCaseCall = 28;
    603603#endif
    604         static const int patchOffsetOpCallCompareToJump = 10;
    605 
    606         static const int patchOffsetMethodCheckProtoObj = 18;
    607         static const int patchOffsetMethodCheckProtoStruct = 28;
    608         static const int patchOffsetMethodCheckPutFunction = 46;
     604        static const int patchOffsetOpCallCompareToJump = 16;
     605
     606        static const int patchOffsetMethodCheckProtoObj = 24;
     607        static const int patchOffsetMethodCheckProtoStruct = 34;
     608        static const int patchOffsetMethodCheckPutFunction = 58;
    609609#elif PLATFORM(ARM_TRADITIONAL)
    610610        // These architecture specific value are used to enable patching - see comment on op_put_by_id.
  • trunk/JavaScriptCore/wtf/Platform.h

    r50218 r50255  
    731731    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
    732732#elif PLATFORM(ARM_THUMB2) && PLATFORM(IPHONE)
    733     /* Under development, temporarily disabled until 16Mb link range limit in assembler is fixed. */
    734     #define ENABLE_JIT 0
     733    #define ENABLE_JIT 1
    735734    #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 0
    736735/* The JIT is tested & working on x86 Windows */
     
    798797#if (PLATFORM(X86) && PLATFORM(MAC)) \
    799798 || (PLATFORM(X86_64) && PLATFORM(MAC)) \
    800  /* Under development, temporarily disabled until 16Mb link range limit in assembler is fixed. */ \
    801  || (PLATFORM(ARM_THUMB2) && PLATFORM(IPHONE) && 0) \
     799 || (PLATFORM(ARM_THUMB2) && PLATFORM(IPHONE)) \
    802800 || (PLATFORM(X86) && PLATFORM(WIN))
    803801#define ENABLE_YARR 1
Note: See TracChangeset for help on using the changeset viewer.