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 332224 9720176011fd9463f950dc335dd1e825634550fb
parent 332223 cb8fa39583a98b02fe0f990369a9c70e42e9b276
child 332225 03c7ee730909e99ec0b88c1ff41025a9e2b669c4
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1277011
milestone50.0a1
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);