Bug 1509562 Part 1 - Remove restriction on redirections being a statically defined array, r=lsmyth.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 23 Nov 2018 09:06:30 -1000
changeset 507403 3f77f0486954f769e7870d02386ea15ca53f82ff
parent 507402 70f4239b2fab7f622de52ba287e6eaa105dd604d
child 507404 bb62b5dc4dbec70a1645b59d6059726f50820ead
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsmyth
bugs1509562
milestone65.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 1509562 Part 1 - Remove restriction on redirections being a statically defined array, r=lsmyth.
toolkit/recordreplay/MiddlemanCall.cpp
toolkit/recordreplay/ProcessRecordReplay.cpp
toolkit/recordreplay/ProcessRedirect.cpp
toolkit/recordreplay/ProcessRedirect.h
toolkit/recordreplay/ProcessRedirectDarwin.cpp
--- a/toolkit/recordreplay/MiddlemanCall.cpp
+++ b/toolkit/recordreplay/MiddlemanCall.cpp
@@ -39,17 +39,17 @@ InitializeMiddlemanCalls()
 // not been sent to the middleman yet, filling aOutgoingCalls with the set of
 // such calls.
 static bool
 GatherDependentCalls(InfallibleVector<MiddlemanCall*>& aOutgoingCalls, MiddlemanCall* aCall)
 {
   MOZ_RELEASE_ASSERT(!aCall->mSent);
   aCall->mSent = true;
 
-  const Redirection& redirection = gRedirections[aCall->mCallId];
+  const Redirection& redirection = GetRedirection(aCall->mCallId);
 
   CallArguments arguments;
   aCall->mArguments.CopyTo(&arguments);
 
   InfallibleVector<MiddlemanCall*> dependentCalls;
 
   MiddlemanCallContext cx(aCall, &arguments, MiddlemanCallPhase::ReplayInput);
   cx.mDependentCalls = &dependentCalls;
@@ -72,17 +72,17 @@ GatherDependentCalls(InfallibleVector<Mi
   return true;
 }
 
 bool
 SendCallToMiddleman(size_t aCallId, CallArguments* aArguments, bool aDiverged)
 {
   MOZ_RELEASE_ASSERT(IsReplaying());
 
-  const Redirection& redirection = gRedirections[aCallId];
+  const Redirection& redirection = GetRedirection(aCallId);
   MOZ_RELEASE_ASSERT(redirection.mMiddlemanCall);
 
   MonitorAutoLock lock(*gMonitor);
 
   // Allocate and fill in a new MiddlemanCall.
   size_t id = gMiddlemanCalls.length();
   MiddlemanCall* newCall = new MiddlemanCall();
   gMiddlemanCalls.emplaceBack(newCall);
@@ -137,17 +137,17 @@ SendCallToMiddleman(size_t aCallId, Call
   for (MiddlemanCall* call : outgoingCalls) {
     call->DecodeOutput(outputStream);
 
     if (call != newCall) {
       CallArguments oldArguments;
       call->mArguments.CopyTo(&oldArguments);
       MiddlemanCallContext cx(call, &oldArguments, MiddlemanCallPhase::ReplayOutput);
       cx.mReplayOutputIsOld = true;
-      gRedirections[call->mCallId].mMiddlemanCall(cx);
+      GetRedirection(call->mCallId).mMiddlemanCall(cx);
     }
   }
 
   // Perform the ReplayOutput phase to fill in outputs for the current call.
   newCall->mArguments.CopyTo(aArguments);
   MiddlemanCallContext cx(newCall, aArguments, MiddlemanCallPhase::ReplayOutput);
   redirection.mMiddlemanCall(cx);
   return true;
@@ -161,17 +161,17 @@ ProcessMiddlemanCall(const char* aInputD
 
   BufferStream inputStream(aInputData, aInputSize);
   BufferStream outputStream(aOutputData);
 
   while (!inputStream.IsEmpty()) {
     MiddlemanCall* call = new MiddlemanCall();
     call->DecodeInput(inputStream);
 
-    const Redirection& redirection = gRedirections[call->mCallId];
+    const Redirection& redirection = GetRedirection(call->mCallId);
     MOZ_RELEASE_ASSERT(redirection.mMiddlemanCall);
 
     CallArguments arguments;
     call->mArguments.CopyTo(&arguments);
 
     {
       MiddlemanCallContext cx(call, &arguments, MiddlemanCallPhase::MiddlemanInput);
       redirection.mMiddlemanCall(cx);
@@ -218,17 +218,17 @@ ResetMiddlemanCalls()
   MOZ_RELEASE_ASSERT(IsMiddleman());
 
   for (MiddlemanCall* call : gMiddlemanCalls) {
     if (call) {
       CallArguments arguments;
       call->mArguments.CopyTo(&arguments);
 
       MiddlemanCallContext cx(call, &arguments, MiddlemanCallPhase::MiddlemanRelease);
-      gRedirections[call->mCallId].mMiddlemanCall(cx);
+      GetRedirection(call->mCallId).mMiddlemanCall(cx);
 
       delete call;
     }
   }
 
   gMiddlemanCalls.clear();
   for (auto buffer : gAllocatedBuffers) {
     free(buffer);
--- a/toolkit/recordreplay/ProcessRecordReplay.cpp
+++ b/toolkit/recordreplay/ProcessRecordReplay.cpp
@@ -321,17 +321,17 @@ ThreadEventName(ThreadEvent aEvent)
 {
   switch (aEvent) {
 #define EnumToString(Kind) case ThreadEvent::Kind: return #Kind;
     ForEachThreadEvent(EnumToString)
 #undef EnumToString
   case ThreadEvent::CallStart: break;
   }
   size_t callId = (size_t) aEvent - (size_t) ThreadEvent::CallStart;
-  return gRedirections[callId].mName;
+  return GetRedirection(callId).mName;
 }
 
 int
 GetRecordingPid()
 {
   return gRecordingPid;
 }
 
--- a/toolkit/recordreplay/ProcessRedirect.cpp
+++ b/toolkit/recordreplay/ProcessRedirect.cpp
@@ -48,17 +48,17 @@ CallPreambleHook(PreambleFn aPreamble, s
   Unreachable();
 }
 
 extern "C" {
 
 __attribute__((used)) int
 RecordReplayInterceptCall(int aCallId, CallArguments* aArguments)
 {
-  Redirection& redirection = gRedirections[aCallId];
+  Redirection& redirection = GetRedirection(aCallId);
 
   // Call the preamble to see if this call needs special handling, even when
   // events have been passed through.
   if (redirection.mPreamble) {
     if (CallPreambleHook(redirection.mPreamble, aCallId, aArguments)) {
       return 0;
     }
   }
@@ -733,32 +733,16 @@ CopyInstructions(const char* aName, uint
 {
   uint8_t* ip = aIpStart;
   while (ip < aIpEnd) {
     ip += CopyInstruction(aName, ip, aAssembler);
   }
   return ip;
 }
 
-// Get the instruction pointer to use as the address of the base function for a
-// redirection.
-static uint8_t*
-FunctionStartAddress(Redirection& aRedirection)
-{
-  uint8_t* addr = static_cast<uint8_t*>(dlsym(RTLD_DEFAULT, aRedirection.mName));
-  if (!addr)
-    return nullptr;
-
-  if (addr[0] == 0xFF && addr[1] == 0x25) {
-    return *(uint8_t**)(addr + 6 + *reinterpret_cast<int32_t*>(addr + 2));
-  }
-
-  return addr;
-}
-
 // Generate code to set %rax and enter RecordReplayRedirectCall.
 static uint8_t*
 GenerateRedirectStub(Assembler& aAssembler, size_t aCallId)
 {
   uint8_t* newFunction = aAssembler.Current();
   aAssembler.MoveImmediateToRax((void*) aCallId);
   aAssembler.Jump(BitwiseCast<void*>(RecordReplayRedirectCall));
   return newFunction;
@@ -904,65 +888,32 @@ Redirect(size_t aCallId, Redirection& aR
 
   // Emit jump J0.
   if (!AddShortJumpPatch(functionStart, ro + JumpBytesClobberRax)) {
     RedirectFailure("Short jump distance too long for %s", aRedirection.mName);
   }
   AddClobberPatch(functionStart + ShortJumpBytes, nro);
 }
 
-void
-EarlyInitializeRedirections()
-{
-  for (size_t i = 0;; i++) {
-    Redirection& redirection = gRedirections[i];
-    if (!redirection.mName) {
-      break;
-    }
-    MOZ_RELEASE_ASSERT(!redirection.mBaseFunction);
-    MOZ_RELEASE_ASSERT(!redirection.mOriginalFunction);
-
-    redirection.mBaseFunction = FunctionStartAddress(redirection);
-    redirection.mOriginalFunction = redirection.mBaseFunction;
-
-    if (redirection.mBaseFunction && IsRecordingOrReplaying()) {
-      // We will get confused if we try to redirect the same address in multiple places.
-      for (size_t j = 0; j < i; j++) {
-        if (gRedirections[j].mBaseFunction == redirection.mBaseFunction) {
-          PrintSpew("Redirection %s shares the same address as %s, skipping.\n",
-                    redirection.mName, gRedirections[j].mName);
-          redirection.mBaseFunction = nullptr;
-          break;
-        }
-      }
-    }
-  }
-}
-
 bool
 InitializeRedirections()
 {
   MOZ_RELEASE_ASSERT(IsRecordingOrReplaying());
 
   {
     Assembler assembler;
+    size_t numRedirections = NumRedirections();
 
-    for (size_t i = 0;; i++) {
-      Redirection& redirection = gRedirections[i];
-      if (!redirection.mName) {
-        break;
-      }
+    for (size_t i = 0; i < numRedirections; i++) {
+      Redirection& redirection = GetRedirection(i);
       Redirect(i, redirection, assembler, /* aFirstPass = */ true);
     }
 
-    for (size_t i = 0;; i++) {
-      Redirection& redirection = gRedirections[i];
-      if (!redirection.mName) {
-        break;
-      }
+    for (size_t i = 0; i < numRedirections; i++) {
+      Redirection& redirection = GetRedirection(i);
       Redirect(i, redirection, assembler, /* aFirstPass = */ false);
     }
   }
 
   // Don't install redirections if we had any failures.
   if (!gRedirectFailures.empty()) {
     nsCString data;
     for (char* reason : gRedirectFailures) {
--- a/toolkit/recordreplay/ProcessRedirect.h
+++ b/toolkit/recordreplay/ProcessRedirect.h
@@ -251,20 +251,21 @@ struct Redirection
   // recording to perform this call in the middleman process.
   MiddlemanCallFn mMiddlemanCall;
 
   // Additional preamble that is only called while replaying and diverged from
   // the recording.
   PreambleFn mMiddlemanPreamble;
 };
 
-// All platform specific redirections, indexed by the call event.
-extern Redirection gRedirections[];
+// Platform specific methods describing the set of redirections.
+size_t NumRedirections();
+Redirection& GetRedirection(size_t aCallId);
 
-// Do early initialization of redirections. This is done on both
+// Platform specific early initialization of redirections. This is done on both
 // recording/replaying and middleman processes, and allows OriginalCall() to
 // work in either case.
 void EarlyInitializeRedirections();
 
 // Set up all platform specific redirections, or fail and set
 // gInitializationFailureMessage.
 bool InitializeRedirections();
 
@@ -277,17 +278,17 @@ static inline void RestoreError(ErrorTyp
 
 // Define CallFunction(...) for all supported ABIs.
 DefineAllCallFunctions(DEFAULTABI)
 
 // Get the address of the original function for a call event ID.
 static inline void*
 OriginalFunction(size_t aCallId)
 {
-  return gRedirections[aCallId].mOriginalFunction;
+  return GetRedirection(aCallId).mOriginalFunction;
 }
 
 #define TokenPaste(aFirst, aSecond) aFirst ## aSecond
 
 // Call the original function for a call event ID with a particular ABI and any
 // number of arguments.
 #define OriginalCallABI(aName, aReturnType, aABI, ...)          \
   TokenPaste(CallFunction, aABI) <aReturnType>                  \
--- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp
+++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp
@@ -2496,23 +2496,76 @@ Preamble_OSSpinLockLock(CallArguments* a
 
 ///////////////////////////////////////////////////////////////////////////////
 // Redirection generation
 ///////////////////////////////////////////////////////////////////////////////
 
 #define MAKE_REDIRECTION_ENTRY(aName, ...)          \
   { #aName, nullptr, nullptr, __VA_ARGS__ },
 
-Redirection gRedirections[] = {
+static Redirection gRedirections[] = {
   FOR_EACH_REDIRECTION(MAKE_REDIRECTION_ENTRY)
-  { }
 };
 
 #undef MAKE_REDIRECTION_ENTRY
 
+size_t
+NumRedirections()
+{
+  return ArrayLength(gRedirections);
+}
+
+Redirection&
+GetRedirection(size_t aCallId)
+{
+  MOZ_RELEASE_ASSERT(aCallId < ArrayLength(gRedirections));
+  return gRedirections[aCallId];
+}
+
+// Get the instruction pointer to use as the address of the base function for a
+// redirection.
+static uint8_t*
+FunctionStartAddress(Redirection& aRedirection)
+{
+  uint8_t* addr = static_cast<uint8_t*>(dlsym(RTLD_DEFAULT, aRedirection.mName));
+  if (!addr)
+    return nullptr;
+
+  if (addr[0] == 0xFF && addr[1] == 0x25) {
+    return *(uint8_t**)(addr + 6 + *reinterpret_cast<int32_t*>(addr + 2));
+  }
+
+  return addr;
+}
+
+void
+EarlyInitializeRedirections()
+{
+  for (size_t i = 0; i < ArrayLength(gRedirections); i++) {
+    Redirection& redirection = gRedirections[i];
+    MOZ_RELEASE_ASSERT(!redirection.mBaseFunction);
+    MOZ_RELEASE_ASSERT(!redirection.mOriginalFunction);
+
+    redirection.mBaseFunction = FunctionStartAddress(redirection);
+    redirection.mOriginalFunction = redirection.mBaseFunction;
+
+    if (redirection.mBaseFunction && IsRecordingOrReplaying()) {
+      // We will get confused if we try to redirect the same address in multiple places.
+      for (size_t j = 0; j < i; j++) {
+        if (gRedirections[j].mBaseFunction == redirection.mBaseFunction) {
+          PrintSpew("Redirection %s shares the same address as %s, skipping.\n",
+                    redirection.mName, gRedirections[j].mName);
+          redirection.mBaseFunction = nullptr;
+          break;
+        }
+      }
+    }
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Direct system call API
 ///////////////////////////////////////////////////////////////////////////////
 
 const char*
 SymbolNameRaw(void* aPtr)
 {
   Dl_info info;