Bug 1277011 - ARM simulator tweaks for dealing with alignment. r=bbouvier
authorLars T Hansen <lhansen@mozilla.com>
Thu, 28 Jul 2016 07:19:46 -0700
changeset 347190 9720176011fd9463f950dc335dd1e825634550fb
parent 347189 cb8fa39583a98b02fe0f990369a9c70e42e9b276
child 347191 03c7ee730909e99ec0b88c1ff41025a9e2b669c4
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1277011
milestone50.0a1
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 1277011 - ARM simulator tweaks for dealing with alignment. r=bbouvier
js/src/jit/arm/Simulator-arm.cpp
js/src/jit/arm/Simulator-arm.h
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -1497,21 +1497,19 @@ Simulator::exclusiveMonitorGetAndClear(b
 
 void
 Simulator::exclusiveMonitorClear()
 {
     exclusiveMonitorHeld_ = false;
 }
 
 int
-Simulator::readW(int32_t addr, SimInstruction* instr)
+Simulator::readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f)
 {
-    // The regexp engine emits unaligned loads, so we don't check for them here
-    // like most of the other methods do.
-    if ((addr & 3) == 0 || !HasAlignmentFault()) {
+    if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
         intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
         return *ptr;
     }
 
     // In WebAssembly, we want unaligned accesses to either raise a signal or
     // do the right thing. Making this simulator properly emulate the behavior
     // of raising a signal is complex, so as a special-case, when in wasm code,
     // we just do the right thing.
@@ -1522,19 +1520,19 @@ Simulator::readW(int32_t addr, SimInstru
         return value;
     }
 
     printf("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
     MOZ_CRASH();
 }
 
 void
-Simulator::writeW(int32_t addr, int value, SimInstruction* instr)
+Simulator::writeW(int32_t addr, int value, SimInstruction* instr, UnalignedPolicy f)
 {
-    if ((addr & 3) == 0 || !HasAlignmentFault()) {
+    if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
         intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
         *ptr = value;
         return;
     }
 
     // See the comments above in readW.
     if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
         char* ptr = reinterpret_cast<char*>(addr);
@@ -1587,70 +1585,104 @@ Simulator::writeExW(int32_t addr, int va
     if ((addr & 3) == 0) {
         SharedMem<int32_t*> ptr = SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
         bool held;
         int32_t expected = int32_t(exclusiveMonitorGetAndClear(&held));
         if (!held)
             return 1;
         int32_t old = compareExchangeRelaxed(ptr, expected, int32_t(value));
         return old != expected;
-    } else {
-        printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
-        MOZ_CRASH();
     }
+
+    printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
+    MOZ_CRASH();
 }
 
 uint16_t
 Simulator::readHU(int32_t addr, SimInstruction* instr)
 {
     // The regexp engine emits unaligned loads, so we don't check for them here
     // like most of the other methods do.
     if ((addr & 1) == 0 || !HasAlignmentFault()) {
         uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
         return *ptr;
     }
+
+    // See comments in readW.
+    if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
+        char* ptr = reinterpret_cast<char*>(addr);
+        uint16_t value;
+        memcpy(&value, ptr, sizeof(value));
+        return value;
+    }
+
     printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
     MOZ_CRASH();
     return 0;
 }
 
 int16_t
 Simulator::readH(int32_t addr, SimInstruction* instr)
 {
     if ((addr & 1) == 0 || !HasAlignmentFault()) {
         int16_t* ptr = reinterpret_cast<int16_t*>(addr);
         return *ptr;
     }
+
+    // See comments in readW.
+    if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
+        char* ptr = reinterpret_cast<char*>(addr);
+        int16_t value;
+        memcpy(&value, ptr, sizeof(value));
+        return value;
+    }
+
     printf("Unaligned signed halfword read at 0x%08x\n", addr);
     MOZ_CRASH();
     return 0;
 }
 
 void
 Simulator::writeH(int32_t addr, uint16_t value, SimInstruction* instr)
 {
     if ((addr & 1) == 0 || !HasAlignmentFault()) {
         uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
         *ptr = value;
-    } else {
-        printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
-        MOZ_CRASH();
+        return;
     }
+
+    // See the comments above in readW.
+    if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
+        char* ptr = reinterpret_cast<char*>(addr);
+        memcpy(ptr, &value, sizeof(value));
+        return;
+    }
+
+    printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
+    MOZ_CRASH();
 }
 
 void
 Simulator::writeH(int32_t addr, int16_t value, SimInstruction* instr)
 {
     if ((addr & 1) == 0 || !HasAlignmentFault()) {
         int16_t* ptr = reinterpret_cast<int16_t*>(addr);
         *ptr = value;
-    } else {
-        printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
-        MOZ_CRASH();
+        return;
     }
+
+    // See the comments above in readW.
+    if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
+        char* ptr = reinterpret_cast<char*>(addr);
+        memcpy(ptr, &value, sizeof(value));
+        return;
+    }
+
+    printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
+    MOZ_CRASH();
 }
 
 uint16_t
 Simulator::readExHU(int32_t addr, SimInstruction* instr)
 {
     // The regexp engine emits unaligned loads, so we don't check for them here
     // like most of the other methods do.
     if ((addr & 1) == 0 || !HasAlignmentFault()) {
@@ -3189,19 +3221,19 @@ Simulator::decodeType2(SimInstruction* i
             uint8_t val = readBU(addr);
             set_register(rd, val);
         } else {
             uint8_t val = get_register(rd);
             writeB(addr, val);
         }
     } else {
         if (instr->hasL())
-            set_register(rd, readW(addr, instr));
+            set_register(rd, readW(addr, instr, AllowUnaligned));
         else
-            writeW(addr, get_register(rd), instr);
+            writeW(addr, get_register(rd), instr, AllowUnaligned);
     }
 }
 
 static uint32_t
 rotateBytes(uint32_t val, int32_t rotate)
 {
     switch (rotate) {
       default:
@@ -3456,19 +3488,19 @@ Simulator::decodeType3(SimInstruction* i
             uint8_t byte = readB(addr);
             set_register(rd, byte);
         } else {
             uint8_t byte = get_register(rd);
             writeB(addr, byte);
         }
     } else {
         if (instr->hasL())
-            set_register(rd, readW(addr, instr));
+            set_register(rd, readW(addr, instr, AllowUnaligned));
         else
-            writeW(addr, get_register(rd), instr);
+            writeW(addr, get_register(rd), instr, AllowUnaligned);
     }
 }
 
 void
 Simulator::decodeType4(SimInstruction* instr)
 {
     // Only allowed to be set in privileged mode.
     MOZ_ASSERT(instr->bit(22) == 0);
@@ -4283,18 +4315,20 @@ Simulator::decodeSpecialCondition(SimIns
               default:
                 MOZ_CRASH();
                 break;
             }
             int r = 0;
             while (r < regs) {
                 uint32_t data[2];
                 get_d_register(Vd + r, data);
-                writeW(address, data[0], instr);
-                writeW(address + 4, data[1], instr);
+                // TODO: We should AllowUnaligned here only if the alignment attribute of
+                // the instruction calls for default alignment.
+                writeW(address, data[0], instr, AllowUnaligned);
+                writeW(address + 4, data[1], instr, AllowUnaligned);
                 address += 8;
                 r++;
             }
             if (Rm != 15) {
                 if (Rm == 13)
                     set_register(Rn, address);
                 else
                     set_register(Rn, get_register(Rn) + get_register(Rm));
@@ -4322,18 +4356,20 @@ Simulator::decodeSpecialCondition(SimIns
                 break;
               default:
                 MOZ_CRASH();
                 break;
             }
             int r = 0;
             while (r < regs) {
                 uint32_t data[2];
-                data[0] = readW(address, instr);
-                data[1] = readW(address + 4, instr);
+                // TODO: We should AllowUnaligned here only if the alignment attribute of
+                // the instruction calls for default alignment.
+                data[0] = readW(address, instr, AllowUnaligned);
+                data[1] = readW(address + 4, instr, AllowUnaligned);
                 set_d_register(Vd + r, data);
                 address += 8;
                 r++;
             }
             if (Rm != 15) {
                 if (Rm == 13)
                     set_register(Rn, address);
                 else
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -199,16 +199,30 @@ class Simulator
         bad_lr = -1,
         // A pc value used to signal the simulator to stop execution. Generally
         // the lr is set to this value on transition from native C code to
         // simulated execution, so that the simulator can "return" to the native
         // C code.
         end_sim_pc = -2
     };
 
+    // ForbidUnaligned means "always fault on unaligned access".
+    //
+    // AllowUnaligned means "allow the unaligned access if other conditions are
+    // met".  The "other conditions" vary with the instruction: For all
+    // instructions the base condition is !HasAlignmentFault(), ie, the chip is
+    // configured to allow unaligned accesses.  For instructions like VLD1
+    // there is an additional constraint that the alignment attribute in the
+    // instruction must be set to "default alignment".
+
+    enum UnalignedPolicy {
+        ForbidUnaligned,
+        AllowUnaligned
+    };
+
     bool init();
 
     // Checks if the current instruction should be executed based on its
     // condition bits.
     inline bool conditionallyExecute(SimInstruction* instr);
 
     // Helper functions to set the conditional flags in the architecture state.
     void setNZFlags(int32_t val);
@@ -256,18 +270,18 @@ class Simulator
     inline int16_t readH(int32_t addr, SimInstruction* instr);
     // Note: Overloaded on the sign of the value.
     inline void writeH(int32_t addr, uint16_t value, SimInstruction* instr);
     inline void writeH(int32_t addr, int16_t value, SimInstruction* instr);
 
     inline uint16_t readExHU(int32_t addr, SimInstruction* instr);
     inline int32_t writeExH(int32_t addr, uint16_t value, SimInstruction* instr);
 
-    inline int readW(int32_t addr, SimInstruction* instr);
-    inline void writeW(int32_t addr, int value, SimInstruction* instr);
+    inline int readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f = ForbidUnaligned);
+    inline void writeW(int32_t addr, int value, SimInstruction* instr, UnalignedPolicy f = ForbidUnaligned);
 
     inline int readExW(int32_t addr, SimInstruction* instr);
     inline int writeExW(int32_t addr, int value, SimInstruction* instr);
 
     int32_t* readDW(int32_t addr);
     void writeDW(int32_t addr, int32_t value1, int32_t value2);
 
     int32_t readExDW(int32_t addr, int32_t* hibits);