Changeset 176083 in webkit


Ignore:
Timestamp:
Nov 13, 2014 12:43:32 PM (9 years ago)
Author:
benjamin@webkit.org
Message:

ARMv7(s) Assembler: LDRH with immediate offset is loading from the wrong offset
https://bugs.webkit.org/show_bug.cgi?id=136914

Reviewed by Michael Saboff.

TLDR: the immediate offset of half-word load was divided by 2.

Story time: So I started getting those weird reports of :nth-child() behaving bizarrely
on ARMv7 and ARMv7s. To make things worse, the behavior changes depending on style updates.

I started looking the disassembly on the tests cases...

The first thing I noticed was that the computation of An+B looked wrong. For example,
in the case of n+6, the instruction should have been:

subs r1, r1, #6

but was

subs r1, r1, #2

After spending a lot of time trying to find the error in the assembler, I discovered
the problem was not real, but just a bug in the disassembler.
This is the first fix: ARMv7DOpcodeAddSubtractImmediate3's immediate3() was truncating
the value to 2 bits instead of 3 bits.

The disassembler being fixed, I still have no lead on the weird bug. Some disassembly later,
I realize the LDRH instruction is not decoded at all. The reason is that both LDRH and STRH
were under the umbrella ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord but the pattern
only matched SRTH.

I fix that next, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord is split into
ARMv7DOpcodeStoreRegisterImmediateHalfWord and ARMv7DOpcodeLoadRegisterImmediateHalfWord,
each with their own pattern and their instruction group.

Now that I can see the LDRHs correctly, there is something fishy about them, their offset
is way too small for the data I load.

This time, looking at the binary, the generated code is indeed incorrect. It turns out that
the ARMv7 assembler shifted the offset of half-word load as if they were byte load: divided by 4.
As a result, all the load of half-words with more than zero offset were loading
values with a smaller offset than what they should have.

That being fixed, I dump the assembly: still wrong. I am ready to throw my keyboard through
my screen at that point.

Looking at the disassembler, there is yet again a bug. The computation of the scale() adjustment
of the offset was incorrect for anything but word loads.
I replaced it by a switch-case to make it explicit.

STRH is likely incorrect too. I'll fix that in a follow up, I want to survey all the 16 bits cases
that are not directly used by the CSS JIT.

  • assembler/ARMv7Assembler.h:

(JSC::ARMv7Assembler::ldrh):
Fix the immediate scaling. Add an assertion to make sure the alignment of the input is correct.

  • disassembler/ARMv7/ARMv7DOpcode.cpp:

(JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale):
Fix the scaling code. Just hardcode instruction-to-scale table.

  • disassembler/ARMv7/ARMv7DOpcode.h:

(JSC::ARMv7Disassembler::ARMv7DOpcodeAddSubtractImmediate3::immediate3):
The mask for a 3 bits immediate is not 3 :)

(JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale): Deleted.

Location:
trunk/Source/JavaScriptCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r176079 r176083  
     12014-11-13  Benjamin Poulain  <benjamin@webkit.org>
     2
     3        ARMv7(s) Assembler: LDRH with immediate offset is loading from the wrong offset
     4        https://bugs.webkit.org/show_bug.cgi?id=136914
     5
     6        Reviewed by Michael Saboff.
     7
     8        TLDR: the immediate offset of half-word load was divided by 2.
     9
     10        Story time: So I started getting those weird reports of :nth-child() behaving bizarrely
     11        on ARMv7 and ARMv7s. To make things worse, the behavior changes depending on style updates.
     12
     13        I started looking the disassembly on the tests cases...
     14
     15        The first thing I noticed was that the computation of An+B looked wrong. For example,
     16        in the case of n+6, the instruction should have been:
     17            subs r1, r1, #6
     18        but was
     19            subs r1, r1, #2
     20
     21        After spending a lot of time trying to find the error in the assembler, I discovered
     22        the problem was not real, but just a bug in the disassembler.
     23        This is the first fix: ARMv7DOpcodeAddSubtractImmediate3's immediate3() was truncating
     24        the value to 2 bits instead of 3 bits.
     25
     26        The disassembler being fixed, I still have no lead on the weird bug. Some disassembly later,
     27        I realize the LDRH instruction is not decoded at all. The reason is that both LDRH and STRH
     28        were under the umbrella ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord but the pattern
     29        only matched SRTH.
     30
     31        I fix that next, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord is split into
     32        ARMv7DOpcodeStoreRegisterImmediateHalfWord and ARMv7DOpcodeLoadRegisterImmediateHalfWord,
     33        each with their own pattern and their instruction group.
     34
     35        Now that I can see the LDRHs correctly, there is something fishy about them, their offset
     36        is way too small for the data I load.
     37
     38        This time, looking at the binary, the generated code is indeed incorrect. It turns out that
     39        the ARMv7 assembler shifted the offset of half-word load as if they were byte load: divided by 4.
     40        As a result, all the load of half-words with more than zero offset were loading
     41        values with a smaller offset than what they should have.
     42
     43        That being fixed, I dump the assembly: still wrong. I am ready to throw my keyboard through
     44        my screen at that point.
     45
     46        Looking at the disassembler, there is yet again a bug. The computation of the scale() adjustment
     47        of the offset was incorrect for anything but word loads.
     48        I replaced it by a switch-case to make it explicit.
     49
     50        STRH is likely incorrect too. I'll fix that in a follow up, I want to survey all the 16 bits cases
     51        that are not directly used by the CSS JIT.
     52
     53        * assembler/ARMv7Assembler.h:
     54        (JSC::ARMv7Assembler::ldrh):
     55        Fix the immediate scaling. Add an assertion to make sure the alignment of the input is correct.
     56
     57        * disassembler/ARMv7/ARMv7DOpcode.cpp:
     58        (JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale):
     59        Fix the scaling code. Just hardcode instruction-to-scale table.
     60
     61        * disassembler/ARMv7/ARMv7DOpcode.h:
     62        (JSC::ARMv7Disassembler::ARMv7DOpcodeAddSubtractImmediate3::immediate3):
     63        The mask for a 3 bits immediate is not 3 :)
     64
     65        (JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale): Deleted.
     66
    1672014-11-13  Andreas Kling  <akling@apple.com>
    268
  • trunk/Source/JavaScriptCore/assembler/ARMv7Assembler.h

    r176072 r176083  
    11561156        ASSERT(rn != ARMRegisters::pc); // LDR (literal)
    11571157        ASSERT(imm.isUInt12());
     1158        ASSERT(!(imm.isUInt12() & 1));
    11581159
    11591160        if (!((rt | rn) & 8) && imm.isUInt6())
    1160             m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt);
     1161            m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 1, rn, rt);
    11611162        else
    11621163            m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12());
  • trunk/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.cpp

    r173312 r176083  
    9292    OPCODE_GROUP_ENTRY(0xe, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
    9393    OPCODE_GROUP_ENTRY(0xf, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
    94     OPCODE_GROUP_ENTRY(0x10, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord),
    95     OPCODE_GROUP_ENTRY(0x11, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord),
     94    OPCODE_GROUP_ENTRY(0x10, ARMv7DOpcodeStoreRegisterImmediateHalfWord),
     95    OPCODE_GROUP_ENTRY(0x11, ARMv7DOpcodeLoadRegisterImmediateHalfWord),
    9696    OPCODE_GROUP_ENTRY(0x12, ARMv7DOpcodeLoadStoreRegisterSPRelative),
    9797    OPCODE_GROUP_ENTRY(0x13, ARMv7DOpcodeLoadStoreRegisterSPRelative),
     
    525525}
    526526
     527unsigned ARMv7DOpcodeLoadStoreRegisterImmediate::scale()
     528{
     529    switch (op()) {
     530    case 0:
     531    case 1:
     532        return 2;
     533    case 2:
     534    case 3:
     535        return 0;
     536    case 4:
     537    case 5:
     538        return 1;
     539    default:
     540        break;
     541    }
     542    ASSERT_NOT_REACHED();
     543    return 0;
     544}
     545
    527546const char* const ARMv7DOpcodeLoadStoreRegisterOffsetT1::s_opNames[8] = {
    528547    "str", "strh", "strb", "ldrsb", "ldr", "ldrh", "ldrb", "ldrsh"
  • trunk/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.h

    r173312 r176083  
    276276
    277277    unsigned op() { return (m_opcode >> 9) & 0x1; }
    278     unsigned immediate3() { return (m_opcode >> 6) & 0x3; }
     278    unsigned immediate3() { return (m_opcode >> 6) & 0x7; }
    279279    unsigned rn() { return (m_opcode >> 3) & 0x7; }
    280280};
     
    442442    unsigned rn() { return (m_opcode >> 3) & 0x7; }
    443443    unsigned rt() { return m_opcode & 0x7; }
    444     unsigned scale() { return 2 - (op() >> 1); }
     444    unsigned scale();
    445445};
    446446
     
    453453};
    454454
    455 class ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
     455class ARMv7DOpcodeStoreRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
    456456public:
    457457    static const uint16_t s_mask = 0xf800;
    458458    static const uint16_t s_pattern = 0x8000;
     459
     460    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
     461};
     462
     463class ARMv7DOpcodeLoadRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
     464public:
     465    static const uint16_t s_mask = 0xf800;
     466    static const uint16_t s_pattern = 0x8800;
    459467
    460468    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
Note: See TracChangeset for help on using the changeset viewer.