Bug 1526276 - Add a fake unwind code to arm64 JIT function entries r=luke
authorDavid Major <dmajor@mozilla.com>
Mon, 25 Feb 2019 21:04:41 +0000
changeset 518866 a00f8b23be0c481a64a48ecfb333338b42833c48
parent 518865 3a11dd127e2c2384564cf162cc73b31c3e525e35
child 518867 7f034553129d9dc4a7e634edb58aee2ed32ee7dc
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1526276
milestone67.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 1526276 - Add a fake unwind code to arm64 JIT function entries r=luke 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