Bug 1320956 - wasm baseline, do not interrupt tableswitch's jump table with other constants. r=bbouvier
authorLars T Hansen <lhansen@mozilla.com>
Fri, 02 Dec 2016 19:42:54 +0100
changeset 325450 3193092d26a96dddb7f112a08d7277c83d9e8f3e
parent 325449 b0dae693fdbc687830ee450a88beec616c43f673
child 325451 9287824003f42411c84cdf4b7b3506371c57a582
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersbbouvier
bugs1320956
milestone53.0a1
Bug 1320956 - wasm baseline, do not interrupt tableswitch's jump table with other constants. r=bbouvier
js/src/wasm/WasmBaselineCompile.cpp
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -2418,58 +2418,72 @@ class BaseCompiler
     // Sundry low-level code generators.
 
     void addInterruptCheck()
     {
         // Always use signals for interrupts with Asm.JS/Wasm
         MOZ_RELEASE_ASSERT(HaveSignalHandlers());
     }
 
-    void jumpTable(LabelVector& labels) {
+    void jumpTable(LabelVector& labels, Label* theTable) {
+        // Flush constant pools to ensure that the table is never interrupted by
+        // constant pool entries.
+        masm.flush();
+
+        masm.bind(theTable);
+
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
         for (uint32_t i = 0; i < labels.length(); i++) {
             CodeLabel cl;
             masm.writeCodePointer(cl.patchAt());
             cl.target()->bind(labels[i]->offset());
             masm.addCodeLabel(cl);
         }
 #else
         MOZ_CRASH("BaseCompiler platform hook: jumpTable");
 #endif
     }
 
-    void tableSwitch(Label* theTable, RegI32 switchValue) {
+    void tableSwitch(Label* theTable, RegI32 switchValue, Label* dispatchCode) {
+        masm.bind(dispatchCode);
+
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
         ScratchI32 scratch(*this);
         CodeLabel tableCl;
 
         masm.mov(tableCl.patchAt(), scratch);
 
         tableCl.target()->bind(theTable->offset());
         masm.addCodeLabel(tableCl);
 
         masm.jmp(Operand(scratch, switchValue, ScalePointer));
 #elif defined(JS_CODEGEN_ARM)
+        // Flush constant pools: offset must reflect the distance from the MOV
+        // to the start of the table; as the address of the MOV is given by the
+        // label, nothing must come between the bind() and the ma_mov().
+        masm.flush();
+
         ScratchI32 scratch(*this);
 
-        // Compute the offset from the next instruction to the jump table
+        // Compute the offset from the ma_mov instruction to the jump table.
         Label here;
         masm.bind(&here);
         uint32_t offset = here.offset() - theTable->offset();
 
         // Read PC+8
         masm.ma_mov(pc, scratch);
 
-        // Required by ma_sub.
+        // ARM scratch register is required by ma_sub.
         ScratchRegisterScope arm_scratch(*this);
 
-        // Compute the table base pointer
+        // Compute the absolute table base pointer into `scratch`, offset by 8
+        // to account for the fact that ma_mov read PC+8.
         masm.ma_sub(Imm32(offset + 8), scratch, arm_scratch);
 
-        // Jump indirect via table element
+        // Jump indirect via table element.
         masm.ma_ldr(DTRAddr(scratch, DtrRegImmShift(switchValue, LSL, 2)), pc, Offset,
                     Assembler::Always);
 #else
         MOZ_CRASH("BaseCompiler platform hook: tableSwitch");
 #endif
     }
 
     RegI32 captureReturnedI32() {
@@ -5530,23 +5544,21 @@ BaseCompiler::emitBrTable()
         uint32_t k = depths[i];
         popStackBeforeBranch(controlItem(k).framePushed);
         masm.jump(controlItem(k).label);
     }
 
     // Emit table.
 
     Label theTable;
-    masm.bind(&theTable);
-    jumpTable(stubs);
+    jumpTable(stubs, &theTable);
 
     // Emit indirect jump.  rc is live here.
 
-    masm.bind(&dispatchCode);
-    tableSwitch(&theTable, rc);
+    tableSwitch(&theTable, rc, &dispatchCode);
 
     deadCode_ = true;
 
     // Clean up.
 
     freeI32(rc);
     freeJoinRegUnlessVoid(r);