Bug 1526276 - Add a fake unwind code to arm64 JIT function entries r=luke a=lizzard
authorDavid Major <dmajor@mozilla.com>
Mon, 25 Feb 2019 21:04:41 +0000
changeset 516189 17fb0284bb5d0ecc4e0f8e87d5738e19fcc6090d
parent 516188 b1350573ac7c6c294c8d5cae275e6cc45b9ffa43
child 516190 e3d40984bde070c97bc3c3190cad373be57b78a9
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke, lizzard
bugs1526276
milestone66.0
Bug 1526276 - Add a fake unwind code to arm64 JIT function entries r=luke a=lizzard This works around the issue where if the PC and SP don't change while unwinding our JIT frame, we'll fail the unwinder's sanity checks and it won't call our exception handler. Ideally we'd store proper unwind info, but that's a larger change for another day. Differential Revision: https://phabricator.services.mozilla.com/D20858
js/src/jit/ProcessExecutableMemory.cpp
--- a/js/src/jit/ProcessExecutableMemory.cpp
+++ b/js/src/jit/ProcessExecutableMemory.cpp
@@ -81,30 +81,26 @@ JS_FRIEND_API void js::SetJitExceptionHa
   MOZ_ASSERT(!sJitExceptionHandler);
   sJitExceptionHandler = handler;
 }
 
 #    if defined(_M_ARM64)
 // See the ".xdata records" section of
 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
 // These records can have various fields present or absent depending on the
-// bits set in the header. We'll be using a mostly-zero dummy structure with
-// no slots for epilogs or unwind codes. But when epilogCount and codeWords are
-// both zero, the interpretation is that there is an additional word containing
-// extended epilog count and code words (which in our case will also be zero).
+// bits set in the header. Our struct will use one 32-bit slot for unwind codes,
+// and no slots for epilog scopes.
 struct UnwindInfo {
   uint32_t functionLength : 18;
   uint32_t version : 2;
   uint32_t hasExceptionHandler : 1;
   uint32_t packedEpilog : 1;
   uint32_t epilogCount : 5;
   uint32_t codeWords : 5;
-  uint16_t extEpilogCount;
-  uint8_t extCodeWords;
-  uint8_t reserved;
+  uint8_t unwindCodes[4];
   uint32_t exceptionHandler;
 };
 static const unsigned ThunkLength = 20;
 #    else
 // From documentation for UNWIND_INFO on
 // http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
 struct UnwindInfo {
   uint8_t version : 3;
@@ -168,16 +164,23 @@ static bool RegisterExecutableMemory(voi
   static_assert(offsetof(ExceptionHandlerRecord, unwindInfo) % 4 == 0,
                 "The ARM64 .pdata format requires that exception information "
                 "RVAs be 4-byte aligned.");
 
   memset(&r->unwindInfo, 0, sizeof(r->unwindInfo));
   r->unwindInfo.hasExceptionHandler = true;
   r->unwindInfo.exceptionHandler = offsetof(ExceptionHandlerRecord, thunk);
 
+  // Use a fake unwind code to make the Windows unwinder do _something_. If the
+  // PC and SP both stay unchanged, we'll fail the unwinder's sanity checks and
+  // it won't call our exception handler.
+  r->unwindInfo.codeWords = 1; // one 32-bit word gives us up to 4 codes
+  r->unwindInfo.unwindCodes[0] = 0b00000001; // alloc_s small stack of size 1*16
+  r->unwindInfo.unwindCodes[1] = 0b11100100; // end
+
   uint32_t* thunk = (uint32_t*)r->thunk;
   uint16_t* addr = (uint16_t*)&handler;
 
   // xip0/r16 should be safe to clobber: Windows just used it to call our thunk.
   const uint8_t reg = 16;
 
   // Say `handler` is 0x4444333322221111, then:
   thunk[0] = 0xd2800000 | addr[0] << 5 | reg;  // mov  xip0, 1111