Merge mozilla-central to autoland. a=merge on a CLOSED TREE
authorRazvan Maries <rmaries@mozilla.com>
Tue, 27 Nov 2018 11:46:29 +0200
changeset 507425 009f60526bb42f964bbefd9feb3213f5651c0ae1
parent 507424 1291883702312b5ca9c44983121ac39fd2b8bdf6 (current diff)
parent 507410 ce39a152428a7f8ba5a4c82455dcf501c76c031b (diff)
child 507426 d61b59d39b4adc3a322609cac931cab5257cbda9
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)
reviewersmerge
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
Merge mozilla-central to autoland. a=merge on a CLOSED TREE
--- a/image/Decoder.h
+++ b/image/Decoder.h
@@ -109,17 +109,17 @@ public:
    * @returns The recycled frame, if any is available.
    */
   virtual RawAccessFrameRef RecycleFrame(gfx::IntRect& aRecycleRect) = 0;
 };
 
 class Decoder
 {
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Decoder)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_RECORDED(Decoder)
 
   explicit Decoder(RasterImage* aImage);
 
   /**
    * Initialize an image decoder. Decoders may not be re-initialized.
    *
    * @return NS_OK if the decoder could be initialized successfully.
    */
--- a/image/IDecodingTask.h
+++ b/image/IDecodingTask.h
@@ -70,17 +70,17 @@ private:
 
 
 /**
  * An IDecodingTask implementation for metadata decodes of images.
  */
 class MetadataDecodingTask final : public IDecodingTask
 {
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MetadataDecodingTask, override)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_RECORDED(MetadataDecodingTask, override)
 
   explicit MetadataDecodingTask(NotNull<Decoder*> aDecoder);
 
   void Run() override;
 
   // Metadata decodes are very fast (since they only need to examine an image's
   // header) so there's no reason to refuse to run them synchronously if the
   // caller will allow us to.
@@ -102,17 +102,17 @@ private:
 
 /**
  * An IDecodingTask implementation for anonymous decoders - that is, decoders
  * with no associated Image object.
  */
 class AnonymousDecodingTask final : public IDecodingTask
 {
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousDecodingTask, override)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_RECORDED(AnonymousDecodingTask, override)
 
   explicit AnonymousDecodingTask(NotNull<Decoder*> aDecoder,
                                  bool aResumable);
 
   void Run() override;
 
   bool ShouldPreferSyncRun() const override { return true; }
   TaskPriority Priority() const override { return TaskPriority::eLow; }
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -630,16 +630,17 @@ js::Nursery::renderProfileJSON(JSONPrint
 
     json.beginObject();
 
     json.property("status", "complete");
 
     json.property("reason", JS::gcreason::ExplainReason(previousGC.reason));
     json.property("bytes_tenured", previousGC.tenuredBytes);
     json.property("cells_tenured", previousGC.tenuredCells);
+    json.property("strings_tenured", stats().getStat(gcstats::STAT_STRINGS_TENURED));
     json.property("bytes_used", previousGC.nurseryUsedBytes);
     json.property("cur_capacity", previousGC.nurseryCapacity);
     const size_t newCapacity = spaceToEnd(maxChunkCount());
     if (newCapacity != previousGC.nurseryCapacity) {
         json.property("new_capacity", newCapacity);
     }
     if (previousGC.nurseryLazyCapacity != previousGC.nurseryCapacity) {
         json.property("lazy_capacity", previousGC.nurseryLazyCapacity);
@@ -656,16 +657,20 @@ js::Nursery::renderProfileJSON(JSONPrint
         json.property("cells_allocated_tenured",
             stats().allocsSinceMinorGCTenured());
     }
 
     if (stats().getStat(gcstats::STAT_OBJECT_GROUPS_PRETENURED)) {
         json.property("groups_pretenured",
             stats().getStat(gcstats::STAT_OBJECT_GROUPS_PRETENURED));
     }
+    if (stats().getStat(gcstats::STAT_NURSERY_STRING_REALMS_DISABLED)) {
+        json.property("nursery_string_realms_disabled",
+            stats().getStat(gcstats::STAT_NURSERY_STRING_REALMS_DISABLED));
+    }
 
     json.beginObjectProperty("phase_times");
 
 #define EXTRACT_NAME(name, text) #name,
     static const char* const names[] = {
 FOR_EACH_NURSERY_PROFILE_TIME(EXTRACT_NAME)
 #undef EXTRACT_NAME
     "" };
@@ -828,37 +833,43 @@ js::Nursery::collect(JS::gcreason::Reaso
                     pretenureCount++;
                 }
             }
         }
     }
     stats().setStat(gcstats::STAT_OBJECT_GROUPS_PRETENURED, pretenureCount);
 
     mozilla::Maybe<AutoGCSession> session;
+    uint32_t numStringsTenured = 0;
+    uint32_t numNurseryStringRealmsDisabled = 0;
     for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
         if (shouldPretenure && zone->allocNurseryStrings && zone->tenuredStrings >= 30 * 1000) {
             if (!session.isSome()) {
                 session.emplace(rt, JS::HeapState::MinorCollecting);
             }
             CancelOffThreadIonCompile(zone);
             bool preserving = zone->isPreservingCode();
             zone->setPreservingCode(false);
             zone->discardJitCode(rt->defaultFreeOp());
             zone->setPreservingCode(preserving);
             for (RealmsInZoneIter r(zone); !r.done(); r.next()) {
                 if (jit::JitRealm* jitRealm = r->jitRealm()) {
                     jitRealm->discardStubs();
                     jitRealm->stringsCanBeInNursery = false;
+                    numNurseryStringRealmsDisabled++;
                 }
             }
             zone->allocNurseryStrings = false;
         }
+        numStringsTenured += zone->tenuredStrings;
         zone->tenuredStrings = 0;
     }
     session.reset(); // End the minor GC session, if running one.
+    stats().setStat(gcstats::STAT_NURSERY_STRING_REALMS_DISABLED, numNurseryStringRealmsDisabled);
+    stats().setStat(gcstats::STAT_STRINGS_TENURED, numStringsTenured);
     endProfile(ProfileKey::Pretenure);
 
     // We ignore gcMaxBytes when allocating for minor collection. However, if we
     // overflowed, we disable the nursery. The next time we allocate, we'll fail
     // because gcBytes >= gcMaxBytes.
     if (rt->gc.usage.gcBytes() >= rt->gc.tunables.gcMaxBytes()) {
         disable();
     }
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -45,19 +45,25 @@ enum Count {
     // Number of arenas relocated by compacting GC.
     COUNT_ARENA_RELOCATED,
 
     COUNT_LIMIT
 };
 
 // Stats can be set with Statistics::setStat(). They're not reset automatically.
 enum Stat {
+    // Number of strings tenured.
+    STAT_STRINGS_TENURED,
+
     // Number of object types pretenured this minor GC.
     STAT_OBJECT_GROUPS_PRETENURED,
 
+    // Number of realms that had nursery strings disabled due to large numbers being tenured.
+    STAT_NURSERY_STRING_REALMS_DISABLED,
+
     STAT_LIMIT
 };
 
 struct ZoneGCStats
 {
     /* Number of zones collected in this GC. */
     int collectedZoneCount = 0;
 
--- a/taskcluster/ci/test/compiled.yml
+++ b/taskcluster/ci/test/compiled.yml
@@ -58,16 +58,17 @@ jittest:
     instance-size:
         by-test-platform:
             android-em.*: xlarge
             default: default
     run-on-projects:
         by-test-platform:
             android-hw.*: ['try']
             linux.*: []  # redundant with SM(...)
+            windows.*: []  # redundant with SM(p)
             default: built-projects
     chunks:
         by-test-platform:
             windows.*: 1
             windows10-64-ccov/debug: 6
             macosx.*: 1
             macosx64-ccov/debug: 4
             android-em-4.3-arm7-api-15/debug: 20
--- a/toolkit/recordreplay/File.cpp
+++ b/toolkit/recordreplay/File.cpp
@@ -154,18 +154,27 @@ Stream::WriteScalar(size_t aValue)
 void
 Stream::RecordOrReplayThreadEvent(ThreadEvent aEvent)
 {
   if (IsRecording()) {
     WriteScalar((size_t) aEvent);
   } else {
     ThreadEvent oldEvent = (ThreadEvent) ReadScalar();
     if (oldEvent != aEvent) {
-      child::ReportFatalError(Nothing(), "Event Mismatch: Recorded %s Replayed %s",
-                              ThreadEventName(oldEvent), ThreadEventName(aEvent));
+      const char* extra = "";
+      if (oldEvent == ThreadEvent::Assert) {
+        // Include the asserted string in the error. This must match up with
+        // the writes in RecordReplayAssert.
+        if (mNameIndex == MainThreadId) {
+          (void) ReadScalar(); // For the ExecutionProgressCounter write below.
+        }
+        extra = ReadInputString();
+      }
+      child::ReportFatalError(Nothing(), "Event Mismatch: Recorded %s %s Replayed %s",
+                              ThreadEventName(oldEvent), extra, ThreadEventName(aEvent));
     }
     mLastEvent = aEvent;
   }
 
   // Check the execution progress counter for events executing on the main thread.
   if (mNameIndex == MainThreadId) {
     CheckInput(*ExecutionProgressCounter());
   }
@@ -180,32 +189,38 @@ Stream::CheckInput(size_t aValue)
     size_t oldValue = ReadScalar();
     if (oldValue != aValue) {
       child::ReportFatalError(Nothing(), "Input Mismatch: %s Recorded %llu Replayed %llu",
                               ThreadEventName(mLastEvent), oldValue, aValue);
     }
   }
 }
 
+const char*
+Stream::ReadInputString()
+{
+  size_t len = ReadScalar();
+  EnsureInputBallast(len + 1);
+  ReadBytes(mInputBallast.get(), len);
+  mInputBallast[len] = 0;
+  return mInputBallast.get();
+}
+
 void
 Stream::CheckInput(const char* aValue)
 {
   size_t len = strlen(aValue);
   if (IsRecording()) {
     WriteScalar(len);
     WriteBytes(aValue, len);
   } else {
-    size_t oldLen = ReadScalar();
-    EnsureInputBallast(oldLen + 1);
-    ReadBytes(mInputBallast.get(), oldLen);
-    mInputBallast[oldLen] = 0;
-
-    if (len != oldLen || memcmp(aValue, mInputBallast.get(), len) != 0) {
+    const char* oldInput = ReadInputString();
+    if (strcmp(oldInput, aValue) != 0) {
       child::ReportFatalError(Nothing(), "Input Mismatch: %s Recorded %s Replayed %s",
-                              ThreadEventName(mLastEvent), mInputBallast.get(), aValue);
+                              ThreadEventName(mLastEvent), oldInput, aValue);
     }
   }
 }
 
 void
 Stream::CheckInput(const void* aData, size_t aSize)
 {
   CheckInput(aSize);
--- a/toolkit/recordreplay/File.h
+++ b/toolkit/recordreplay/File.h
@@ -192,16 +192,17 @@ private:
     DontCopyExistingData,
     CopyExistingData
   };
 
   void EnsureMemory(UniquePtr<char[]>* aBuf, size_t* aSize, size_t aNeededSize, size_t aMaxSize,
                     ShouldCopy aCopy);
   void EnsureInputBallast(size_t aSize);
   void Flush(bool aTakeLock);
+  const char* ReadInputString();
 
   static size_t BallastMaxSize();
 };
 
 class File
 {
 public:
   enum Mode {
--- a/toolkit/recordreplay/MiddlemanCall.cpp
+++ b/toolkit/recordreplay/MiddlemanCall.cpp
@@ -39,25 +39,31 @@ 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 = GetRedirection(aCall->mCallId);
+
   CallArguments arguments;
   aCall->mArguments.CopyTo(&arguments);
 
   InfallibleVector<MiddlemanCall*> dependentCalls;
 
   MiddlemanCallContext cx(aCall, &arguments, MiddlemanCallPhase::ReplayInput);
   cx.mDependentCalls = &dependentCalls;
-  gRedirections[aCall->mCallId].mMiddlemanCall(cx);
+  redirection.mMiddlemanCall(cx);
   if (cx.mFailed) {
+    if (child::CurrentRepaintCannotFail()) {
+      child::ReportFatalError(Nothing(), "Middleman call input failed: %s\n",
+                              redirection.mName);
+    }
     return false;
   }
 
   for (MiddlemanCall* dependent : dependentCalls) {
     if (!dependent->mSent && !GatherDependentCalls(aOutgoingCalls, dependent)) {
       return false;
     }
   }
@@ -66,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);
@@ -86,16 +92,20 @@ SendCallToMiddleman(size_t aCallId, Call
 
   // Perform the ReplayPreface phase on the new call.
   {
     MiddlemanCallContext cx(newCall, aArguments, MiddlemanCallPhase::ReplayPreface);
     redirection.mMiddlemanCall(cx);
     if (cx.mFailed) {
       delete newCall;
       gMiddlemanCalls.popBack();
+      if (child::CurrentRepaintCannotFail()) {
+        child::ReportFatalError(Nothing(), "Middleman call preface failed: %s\n",
+                                redirection.mName);
+      }
       return false;
     }
   }
 
   // Other phases will not run if we have not diverged from the recording.
   // Any outputs for the call have been handled by the SaveOutput hook.
   if (!aDiverged) {
     return true;
@@ -127,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;
@@ -151,28 +161,28 @@ 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);
     }
 
-    RecordReplayInvokeCall(call->mCallId, &arguments);
+    RecordReplayInvokeCall(redirection.mBaseFunction, &arguments);
 
     {
       MiddlemanCallContext cx(call, &arguments, MiddlemanCallPhase::MiddlemanOutput);
       redirection.mMiddlemanCall(cx);
     }
 
     call->mArguments.CopyFrom(&arguments);
     call->EncodeOutput(outputStream);
@@ -208,27 +218,32 @@ 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;
-    }
+  // Delete the calls in a second pass. The MiddlemanRelease phase depends on
+  // previous middleman calls still existing.
+  for (MiddlemanCall* call : gMiddlemanCalls) {
+    delete call;
   }
 
   gMiddlemanCalls.clear();
   for (auto buffer : gAllocatedBuffers) {
     free(buffer);
   }
   gAllocatedBuffers.clear();
+  gMiddlemanCallMap->clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // System Values
 ///////////////////////////////////////////////////////////////////////////////
 
 static void
 AddMiddlemanCallValue(const void* aThing, MiddlemanCall* aCall)
@@ -253,17 +268,17 @@ GetMiddlemanCallValue(size_t aId)
   MOZ_RELEASE_ASSERT(IsMiddleman());
   MOZ_RELEASE_ASSERT(aId < gMiddlemanCalls.length() &&
                      gMiddlemanCalls[aId] &&
                      gMiddlemanCalls[aId]->mMiddlemanValue.isSome());
   return gMiddlemanCalls[aId]->mMiddlemanValue.ref();
 }
 
 bool
-Middleman_SystemInput(MiddlemanCallContext& aCx, const void** aThingPtr)
+MM_SystemInput(MiddlemanCallContext& aCx, const void** aThingPtr)
 {
   MOZ_RELEASE_ASSERT(aCx.AccessPreface());
 
   if (!*aThingPtr) {
     // Null values are handled by the normal argument copying logic.
     return true;
   }
 
@@ -309,17 +324,17 @@ Middleman_SystemInput(MiddlemanCallConte
 // which originate from different processes.
 static const void*
 MangleSystemValue(const void* aValue, bool aFromRecording)
 {
   return (const void*) ((size_t)aValue | (1ULL << (aFromRecording ? 63 : 62)));
 }
 
 void
-Middleman_SystemOutput(MiddlemanCallContext& aCx, const void** aOutput, bool aUpdating)
+MM_SystemOutput(MiddlemanCallContext& aCx, const void** aOutput, bool aUpdating)
 {
   if (!*aOutput) {
     if (aCx.mPhase == MiddlemanCallPhase::MiddlemanOutput) {
       aCx.mCall->SetMiddlemanValue(*aOutput);
     }
     return;
   }
 
--- a/toolkit/recordreplay/MiddlemanCall.h
+++ b/toolkit/recordreplay/MiddlemanCall.h
@@ -351,114 +351,114 @@ void ResetMiddlemanCalls();
 
 ///////////////////////////////////////////////////////////////////////////////
 // Middleman Call Helpers
 ///////////////////////////////////////////////////////////////////////////////
 
 // Capture the contents of an input buffer at BufferArg with element count at CountArg.
 template <size_t BufferArg, size_t CountArg, typename ElemType = char>
 static inline void
-Middleman_Buffer(MiddlemanCallContext& aCx)
+MM_Buffer(MiddlemanCallContext& aCx)
 {
   if (aCx.AccessPreface()) {
     auto& buffer = aCx.mArguments->Arg<BufferArg, void*>();
     auto byteSize = aCx.mArguments->Arg<CountArg, size_t>() * sizeof(ElemType);
     aCx.ReadOrWritePrefaceBuffer(&buffer, byteSize);
   }
 }
 
 // Capture the contents of a fixed size input buffer.
 template <size_t BufferArg, size_t ByteSize>
 static inline void
-Middleman_BufferFixedSize(MiddlemanCallContext& aCx)
+MM_BufferFixedSize(MiddlemanCallContext& aCx)
 {
   if (aCx.AccessPreface()) {
     auto& buffer = aCx.mArguments->Arg<BufferArg, void*>();
     if (buffer) {
       aCx.ReadOrWritePrefaceBuffer(&buffer, ByteSize);
     }
   }
 }
 
 // Capture a C string argument.
 template <size_t StringArg>
 static inline void
-Middleman_CString(MiddlemanCallContext& aCx)
+MM_CString(MiddlemanCallContext& aCx)
 {
   if (aCx.AccessPreface()) {
     auto& buffer = aCx.mArguments->Arg<StringArg, char*>();
     size_t len = (aCx.mPhase == MiddlemanCallPhase::ReplayPreface) ? strlen(buffer) + 1 : 0;
     aCx.ReadOrWritePrefaceBytes(&len, sizeof(len));
     aCx.ReadOrWritePrefaceBuffer((void**) &buffer, len);
   }
 }
 
 // Capture the data written to an output buffer at BufferArg with element count at CountArg.
 template <size_t BufferArg, size_t CountArg, typename ElemType>
 static inline void
-Middleman_WriteBuffer(MiddlemanCallContext& aCx)
+MM_WriteBuffer(MiddlemanCallContext& aCx)
 {
   auto& buffer = aCx.mArguments->Arg<BufferArg, void*>();
   auto count = aCx.mArguments->Arg<CountArg, size_t>();
   aCx.ReadOrWriteOutputBuffer(&buffer, count * sizeof(ElemType));
 }
 
 // Capture the data written to a fixed size output buffer.
 template <size_t BufferArg, size_t ByteSize>
 static inline void
-Middleman_WriteBufferFixedSize(MiddlemanCallContext& aCx)
+MM_WriteBufferFixedSize(MiddlemanCallContext& aCx)
 {
   auto& buffer = aCx.mArguments->Arg<BufferArg, void*>();
   aCx.ReadOrWriteOutputBuffer(&buffer, ByteSize);
 }
 
 // Capture return values that are too large for register storage.
 template <size_t ByteSize>
 static inline void
-Middleman_OversizeRval(MiddlemanCallContext& aCx)
+MM_OversizeRval(MiddlemanCallContext& aCx)
 {
-  Middleman_WriteBufferFixedSize<0, ByteSize>(aCx);
+  MM_WriteBufferFixedSize<0, ByteSize>(aCx);
 }
 
 // Capture a byte count of stack argument data.
 template <size_t ByteSize>
 static inline void
-Middleman_StackArgumentData(MiddlemanCallContext& aCx)
+MM_StackArgumentData(MiddlemanCallContext& aCx)
 {
   if (aCx.AccessPreface()) {
     auto stack = aCx.mArguments->StackAddress<0>();
     aCx.ReadOrWritePrefaceBytes(stack, ByteSize);
   }
 }
 
 static inline void
-Middleman_NoOp(MiddlemanCallContext& aCx)
+MM_NoOp(MiddlemanCallContext& aCx)
 {
 }
 
 template <MiddlemanCallFn Fn0,
           MiddlemanCallFn Fn1,
-          MiddlemanCallFn Fn2 = Middleman_NoOp,
-          MiddlemanCallFn Fn3 = Middleman_NoOp,
-          MiddlemanCallFn Fn4 = Middleman_NoOp>
+          MiddlemanCallFn Fn2 = MM_NoOp,
+          MiddlemanCallFn Fn3 = MM_NoOp,
+          MiddlemanCallFn Fn4 = MM_NoOp>
 static inline void
-Middleman_Compose(MiddlemanCallContext& aCx)
+MM_Compose(MiddlemanCallContext& aCx)
 {
   Fn0(aCx);
   Fn1(aCx);
   Fn2(aCx);
   Fn3(aCx);
   Fn4(aCx);
 }
 
 // Helper for capturing inputs that are produced by other middleman calls.
 // Returns false in the ReplayInput or MiddlemanInput phases if the input
 // system value could not be found.
-bool Middleman_SystemInput(MiddlemanCallContext& aCx, const void** aThingPtr);
+bool MM_SystemInput(MiddlemanCallContext& aCx, const void** aThingPtr);
 
 // Helper for capturing output system values that might be consumed by other
 // middleman calls.
-void Middleman_SystemOutput(MiddlemanCallContext& aCx, const void** aOutput, bool aUpdating = false);
+void MM_SystemOutput(MiddlemanCallContext& aCx, const void** aOutput, bool aUpdating = false);
 
 } // namespace recordreplay
 } // namespace mozilla
 
 #endif // mozilla_recordreplay_MiddlemanCall_h
--- a/toolkit/recordreplay/ProcessRecordReplay.cpp
+++ b/toolkit/recordreplay/ProcessRecordReplay.cpp
@@ -129,16 +129,17 @@ RecordReplayInterface_Initialize(int aAr
   } else {
     gInitializationFailureMessage = strdup("Bad recording file");
   }
 
   if (gInitializationFailureMessage) {
     fprintf(stderr, "Initialization Failure: %s\n", gInitializationFailureMessage);
   }
 
+  LateInitializeRedirections();
   Thread::InitializeThreads();
 
   Thread* thread = Thread::GetById(MainThreadId);
   MOZ_ASSERT(thread->Id() == MainThreadId);
 
   thread->BindToCurrent();
   thread->SetPassThrough(true);
 
@@ -321,17 +322,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;
 }
 
@@ -349,16 +350,18 @@ RecordReplayInterface_InternalRecordRepl
   if (!res.CanAccessEvents()) {
     return;
   }
 
   // Add the asserted string to the recording.
   char text[1024];
   VsprintfLiteral(text, aFormat, aArgs);
 
+  // This must be kept in sync with Stream::RecordOrReplayThreadEvent, which
+  // peeks at the input string written after the thread event.
   thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Assert);
   thread->Events().CheckInput(text);
 }
 
 MOZ_EXPORT void
 RecordReplayInterface_InternalRecordReplayAssertBytes(const void* aData, size_t aSize)
 {
   Thread* thread = Thread::Current();
--- a/toolkit/recordreplay/ProcessRedirect.cpp
+++ b/toolkit/recordreplay/ProcessRedirect.cpp
@@ -34,31 +34,31 @@ static bool
 CallPreambleHook(PreambleFn aPreamble, size_t aCallId, CallArguments* aArguments)
 {
   PreambleResult result = aPreamble(aArguments);
   switch (result) {
   case PreambleResult::Veto:
     return true;
   case PreambleResult::PassThrough: {
     AutoEnsurePassThroughThreadEvents pt;
-    RecordReplayInvokeCall(aCallId, aArguments);
+    RecordReplayInvokeCall(OriginalFunction(aCallId), aArguments);
     return true;
   }
   case PreambleResult::Redirect:
     return false;
   }
   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;
     }
   }
@@ -115,17 +115,17 @@ RecordReplayInterceptCall(int aCallId, C
   }
 
   if (IsRecording()) {
     // Call the original function, passing through events while we do so.
     // Destroy the RecordingEventSection so that we don't prevent the file
     // from being flushed in case we end up blocking.
     res.reset();
     thread->SetPassThrough(true);
-    RecordReplayInvokeCall(aCallId, aArguments);
+    RecordReplayInvokeCall(redirection.mOriginalFunction, aArguments);
     thread->SetPassThrough(false);
     res.emplace(thread);
   }
 
   // Save any system error in case we want to record/replay it.
   ErrorType error = SaveError();
 
   // Add an event for the thread.
@@ -282,19 +282,19 @@ RecordReplayInvokeCallRaw(CallArguments*
   "movsd %xmm1, 96(%rdi);"
 
   "ret;"
 );
 
 } // extern "C"
 
 MOZ_NEVER_INLINE void
-RecordReplayInvokeCall(size_t aCallId, CallArguments* aArguments)
+RecordReplayInvokeCall(void* aFunction, CallArguments* aArguments)
 {
-  RecordReplayInvokeCallRaw(aArguments, OriginalFunction(aCallId));
+  RecordReplayInvokeCallRaw(aArguments, aFunction);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Library API Redirections
 ///////////////////////////////////////////////////////////////////////////////
 
 // Redirecting system library APIs requires delicacy. We have to patch the code
 // so that whenever control reaches the beginning of the library API's symbol,
@@ -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) {
@@ -997,16 +948,29 @@ InitializeRedirections()
     for (uint8_t* ip = patch.mStart; ip < patch.mEnd; ip++) {
       Assembler::PatchClobber(ip);
     }
   }
 
   return true;
 }
 
+void*
+OriginalFunction(const char* aName)
+{
+  size_t numRedirections = NumRedirections();
+  for (size_t i = 0; i < numRedirections; i++) {
+    const Redirection& redirection = GetRedirection(i);
+    if (!strcmp(aName, redirection.mName)) {
+      return redirection.mOriginalFunction;
+    }
+  }
+  MOZ_CRASH("OriginalFunction: unknown redirection");
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Utility
 ///////////////////////////////////////////////////////////////////////////////
 
 Atomic<size_t, SequentiallyConsistent, Behavior::DontPreserve> gMemoryLeakBytes;
 
 void*
 BindFunctionArgument(void* aFunction, void* aArgument, size_t aArgumentPosition,
--- a/toolkit/recordreplay/ProcessRedirect.h
+++ b/toolkit/recordreplay/ProcessRedirect.h
@@ -109,37 +109,45 @@ public:
 // were initially invoked.
 //
 // Arguments and return value indexes refer to the register contents as passed
 // to the function originally. For functions with complex or floating point
 // arguments and return values, the right index to use might be different than
 // expected, per the requirements of the System V x64 ABI.
 struct CallArguments : public CallRegisterArguments
 {
+  // The maximum number of stack arguments that can be captured.
+  static const size_t NumStackArguments = 64;
+
 protected:
-  size_t stack[64]; // 104
-                    // Size: 616
+  size_t stack[NumStackArguments]; // 104
+                                   // Size: 616
 
 public:
-  template <size_t Index, typename T>
-  T& Arg() {
+  template <typename T>
+  T& Arg(size_t aIndex) {
     static_assert(sizeof(T) == sizeof(size_t), "Size must match");
     static_assert(IsFloatingPoint<T>::value == false, "FloatArg NYI");
-    static_assert(Index < 70, "Bad index");
-    switch (Index) {
+    MOZ_RELEASE_ASSERT(aIndex < 70);
+    switch (aIndex) {
     case 0: return (T&)arg0;
     case 1: return (T&)arg1;
     case 2: return (T&)arg2;
     case 3: return (T&)arg3;
     case 4: return (T&)arg4;
     case 5: return (T&)arg5;
-    default: return (T&)stack[Index - 6];
+    default: return (T&)stack[aIndex - 6];
     }
   }
 
+  template <size_t Index, typename T>
+  T& Arg() {
+    return Arg<T>(Index);
+  }
+
   template <size_t Offset>
   size_t* StackAddress() {
     static_assert(Offset % sizeof(size_t) == 0, "Bad stack offset");
     return &stack[Offset / sizeof(size_t)];
   }
 
   template <typename T, size_t Index = 0>
   T& Rval() {
@@ -243,65 +251,61 @@ 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();
 
+// Platform specific function called after setting up redirections in recording
+// or replaying processes.
+void LateInitializeRedirections();
+
 // Functions for saving or restoring system error codes.
 static inline ErrorType SaveError() { return errno; }
 static inline void RestoreError(ErrorType aError) { errno = aError; }
 
 // Specify the default ABI to use by the record/replay macros below.
 #define DEFAULTABI
 
 // 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>                  \
-    (OriginalFunction(CallEvent_ ##aName), ##__VA_ARGS__)
-
-// Call the original function for a call event ID with the default ABI.
-#define OriginalCall(aName, aReturnType, ...)                   \
-  OriginalCallABI(aName, aReturnType, DEFAULTABI, ##__VA_ARGS__)
+// Get the address of the original function by name.
+void* OriginalFunction(const char* aName);
 
 static inline ThreadEvent
 CallIdToThreadEvent(size_t aCallId)
 {
   return (ThreadEvent)((uint32_t)ThreadEvent::CallStart + aCallId);
 }
 
 void
-RecordReplayInvokeCall(size_t aCallId, CallArguments* aArguments);
+RecordReplayInvokeCall(void* aFunction, CallArguments* aArguments);
 
 ///////////////////////////////////////////////////////////////////////////////
 // Callback Redirections
 ///////////////////////////////////////////////////////////////////////////////
 
 // Below are helpers for use in handling a common callback pattern used within
 // redirections: the system is passed a pointer to a Gecko callback, and a
 // pointer to some opaque Gecko data which the system will pass to the callback
--- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp
+++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp
@@ -37,612 +37,56 @@
 
 #include <Carbon/Carbon.h>
 #include <SystemConfiguration/SystemConfiguration.h>
 #include <objc/objc-runtime.h>
 
 namespace mozilla {
 namespace recordreplay {
 
-// Specify every function that is being redirected. MACRO is invoked with the
-// function's name, followed by any hooks associated with the redirection for
-// saving its output or adding a preamble.
-#define FOR_EACH_REDIRECTION(MACRO)                              \
-  /* System call wrappers */                                     \
-  MACRO(kevent, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<3, 4, struct kevent>>, \
-        nullptr, nullptr, Preamble_WaitForever)                  \
-  MACRO(kevent64, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<3, 4, struct kevent64_s>>) \
-  MACRO(mprotect, nullptr, Preamble_mprotect)                    \
-  MACRO(mmap, nullptr, Preamble_mmap)                            \
-  MACRO(munmap, nullptr, Preamble_munmap)                        \
-  MACRO(read, RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>>, \
-        nullptr, nullptr, Preamble_SetError<EIO>)                \
-  MACRO(__read_nocancel, RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>>) \
-  MACRO(pread, RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>>) \
-  MACRO(write, RR_SaveRvalHadErrorNegative,                      \
-        nullptr, nullptr, MiddlemanPreamble_write)               \
-  MACRO(__write_nocancel, RR_SaveRvalHadErrorNegative)           \
-  MACRO(open, RR_SaveRvalHadErrorNegative)                       \
-  MACRO(__open_nocancel, RR_SaveRvalHadErrorNegative)            \
-  MACRO(recv, RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>>) \
-  MACRO(recvmsg, RR_SaveRvalHadErrorNegative<RR_recvmsg>,        \
-        nullptr, nullptr, Preamble_WaitForever)                  \
-  MACRO(sendmsg, RR_SaveRvalHadErrorNegative,                    \
-        nullptr, nullptr, MiddlemanPreamble_sendmsg)             \
-  MACRO(shm_open, RR_SaveRvalHadErrorNegative)                   \
-  MACRO(socket, RR_SaveRvalHadErrorNegative)                     \
-  MACRO(kqueue, RR_SaveRvalHadErrorNegative)                     \
-  MACRO(pipe, RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<0, 2 * sizeof(int)>>, \
-        nullptr, nullptr, Preamble_SetError)                     \
-  MACRO(close, RR_SaveRvalHadErrorNegative, nullptr, nullptr, Preamble_Veto<0>) \
-  MACRO(__close_nocancel, RR_SaveRvalHadErrorNegative)           \
-  MACRO(mkdir, RR_SaveRvalHadErrorNegative)                      \
-  MACRO(dup, RR_SaveRvalHadErrorNegative)                        \
-  MACRO(access, RR_SaveRvalHadErrorNegative, nullptr, nullptr, Preamble_SetError<EACCES>) \
-  MACRO(lseek, RR_SaveRvalHadErrorNegative)                      \
-  MACRO(socketpair, RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<3, 2 * sizeof(int)>>) \
-  MACRO(fileport_makeport,                                       \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(size_t)>>) \
-  MACRO(getsockopt, RR_SaveRvalHadErrorNegative<RR_getsockopt>)  \
-  MACRO(gettimeofday, RR_SaveRvalHadErrorNegative<RR_Compose<    \
-                        RR_WriteOptionalBufferFixedSize<0, sizeof(struct timeval)>, \
-                        RR_WriteOptionalBufferFixedSize<1, sizeof(struct timezone)>>>, \
-        nullptr, nullptr, Preamble_PassThrough)                  \
-  MACRO(getuid, RR_ScalarRval)                                   \
-  MACRO(geteuid, RR_ScalarRval)                                  \
-  MACRO(getgid, RR_ScalarRval)                                   \
-  MACRO(getegid, RR_ScalarRval)                                  \
-  MACRO(issetugid, RR_ScalarRval)                                \
-  MACRO(__gettid, RR_ScalarRval)                                 \
-  MACRO(getpid, nullptr, Preamble_getpid)                        \
-  MACRO(fcntl, RR_SaveRvalHadErrorNegative, Preamble_fcntl, nullptr, MiddlemanPreamble_fcntl) \
-  MACRO(getattrlist, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<2, 3>>) \
-  MACRO(fstat$INODE64,                                           \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct stat)>>, \
-        nullptr, nullptr, Preamble_SetError)                     \
-  MACRO(lstat$INODE64,                                           \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct stat)>>, \
-        nullptr, nullptr, Preamble_SetError)                     \
-  MACRO(stat$INODE64,                                            \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct stat)>>, \
-        nullptr, nullptr, Preamble_SetError)                     \
-  MACRO(statfs$INODE64,                                          \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct statfs)>>, \
-        nullptr, nullptr, Preamble_SetError)                     \
-  MACRO(fstatfs$INODE64,                                         \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct statfs)>>, \
-        nullptr, nullptr, Preamble_SetError)                     \
-  MACRO(readlink, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<1, 2>>) \
-  MACRO(__getdirentries64, RR_SaveRvalHadErrorNegative<RR_Compose< \
-                             RR_WriteBuffer<1, 2>,               \
-                             RR_WriteBufferFixedSize<3, sizeof(size_t)>>>) \
-  MACRO(getdirentriesattr, RR_SaveRvalHadErrorNegative<RR_Compose< \
-                             RR_WriteBufferFixedSize<1, sizeof(struct attrlist)>, \
-                             RR_WriteBuffer<2, 3>,               \
-                             RR_WriteBufferFixedSize<4, sizeof(size_t)>, \
-                             RR_WriteBufferFixedSize<5, sizeof(size_t)>, \
-                             RR_WriteBufferFixedSize<6, sizeof(size_t)>>>) \
-  MACRO(getrusage,                                               \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct rusage)>>, \
-        nullptr, nullptr, Preamble_PassThrough)                  \
-  MACRO(__getrlimit,                                             \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct rlimit)>>) \
-  MACRO(__setrlimit, RR_SaveRvalHadErrorNegative)                \
-  MACRO(sigprocmask,                                             \
-        RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(sigset_t)>>, \
-        nullptr, nullptr, Preamble_PassThrough)                  \
-  MACRO(sigaltstack,                                             \
-        RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(stack_t)>>) \
-  MACRO(sigaction,                                               \
-        RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(struct sigaction)>>) \
-  MACRO(__pthread_sigmask,                                       \
-        RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(sigset_t)>>) \
-  MACRO(__fsgetpath, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<0, 1>>) \
-  MACRO(__disable_threadsignal, nullptr, Preamble___disable_threadsignal) \
-  MACRO(__sysctl, RR_SaveRvalHadErrorNegative<RR___sysctl>)      \
-  MACRO(__mac_syscall, RR_SaveRvalHadErrorNegative)              \
-  MACRO(getaudit_addr,                                           \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<0, sizeof(auditinfo_addr_t)>>) \
-  MACRO(umask, RR_ScalarRval)                                    \
-  MACRO(__select, RR_SaveRvalHadErrorNegative<RR_Compose<        \
-                    RR_WriteBufferFixedSize<1, sizeof(fd_set)>,  \
-                    RR_WriteBufferFixedSize<2, sizeof(fd_set)>,  \
-                    RR_WriteBufferFixedSize<3, sizeof(fd_set)>,  \
-                    RR_WriteOptionalBufferFixedSize<4, sizeof(timeval)>>>, \
-        nullptr, nullptr, Preamble_WaitForever)                  \
-  MACRO(__process_policy, RR_SaveRvalHadErrorNegative)           \
-  MACRO(__kdebug_trace, RR_SaveRvalHadErrorNegative)             \
-  MACRO(guarded_kqueue_np,                                       \
-        RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<0, sizeof(size_t)>>) \
-  MACRO(csops, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<2, 3>>) \
-  MACRO(__getlogin, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<0, 1>>) \
-  MACRO(__workq_kernreturn, nullptr, Preamble___workq_kernreturn) \
-  MACRO(start_wqthread, nullptr, Preamble_start_wqthread)        \
-  /* pthreads interface functions */                             \
-  MACRO(pthread_cond_wait, nullptr, Preamble_pthread_cond_wait)  \
-  MACRO(pthread_cond_timedwait, nullptr, Preamble_pthread_cond_timedwait) \
-  MACRO(pthread_cond_timedwait_relative_np, nullptr, Preamble_pthread_cond_timedwait_relative_np) \
-  MACRO(pthread_create, nullptr, Preamble_pthread_create)        \
-  MACRO(pthread_join, nullptr, Preamble_pthread_join)            \
-  MACRO(pthread_mutex_init, nullptr, Preamble_pthread_mutex_init) \
-  MACRO(pthread_mutex_destroy, nullptr, Preamble_pthread_mutex_destroy) \
-  MACRO(pthread_mutex_lock, nullptr, Preamble_pthread_mutex_lock) \
-  MACRO(pthread_mutex_trylock, nullptr, Preamble_pthread_mutex_trylock) \
-  MACRO(pthread_mutex_unlock, nullptr, Preamble_pthread_mutex_unlock) \
-  /* C Library functions */                                      \
-  MACRO(dlclose, nullptr, Preamble_Veto<0>)                      \
-  MACRO(dlopen, nullptr, Preamble_PassThrough)                   \
-  MACRO(dlsym, nullptr, Preamble_PassThrough)                    \
-  MACRO(fclose, RR_SaveRvalHadErrorNegative)                     \
-  MACRO(fopen, RR_SaveRvalHadErrorZero)                          \
-  MACRO(fread, RR_Compose<RR_ScalarRval, RR_fread>)              \
-  MACRO(fseek, RR_SaveRvalHadErrorNegative)                      \
-  MACRO(ftell, RR_SaveRvalHadErrorNegative)                      \
-  MACRO(fwrite, RR_ScalarRval)                                   \
-  MACRO(getenv, RR_CStringRval, Preamble_getenv, nullptr, Preamble_Veto<0>) \
-  MACRO(localtime_r,                                             \
-        RR_SaveRvalHadErrorZero<RR_Compose<RR_WriteBufferFixedSize<1, sizeof(struct tm)>, \
-                                RR_RvalIsArgument<1>>>,          \
-        nullptr, nullptr, Preamble_PassThrough)                  \
-  MACRO(gmtime_r,                                                \
-        RR_SaveRvalHadErrorZero<RR_Compose<RR_WriteBufferFixedSize<1, sizeof(struct tm)>, \
-                                RR_RvalIsArgument<1>>>,          \
-        nullptr, nullptr, Preamble_PassThrough)                  \
-  MACRO(localtime, nullptr, Preamble_localtime, nullptr, Preamble_PassThrough) \
-  MACRO(gmtime, nullptr, Preamble_gmtime, nullptr, Preamble_PassThrough) \
-  MACRO(mktime, RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(struct tm)>>) \
-  MACRO(setlocale, RR_CStringRval)                               \
-  MACRO(strftime, RR_Compose<RR_ScalarRval, RR_WriteBufferViaRval<0, 1, 1>>) \
-  MACRO(arc4random, RR_ScalarRval, nullptr, nullptr, Preamble_PassThrough) \
-  MACRO(mach_absolute_time, RR_ScalarRval, Preamble_mach_absolute_time, \
-        nullptr, Preamble_PassThrough)                           \
-  MACRO(mach_msg, RR_Compose<RR_ScalarRval, RR_WriteBuffer<0, 3>>, \
-        nullptr, nullptr, Preamble_WaitForever)                  \
-  MACRO(mach_timebase_info,                                      \
-        RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(mach_timebase_info_data_t)>>) \
-  MACRO(mach_vm_allocate, nullptr, Preamble_mach_vm_allocate)    \
-  MACRO(mach_vm_deallocate, nullptr, Preamble_mach_vm_deallocate) \
-  MACRO(mach_vm_map, nullptr, Preamble_mach_vm_map)              \
-  MACRO(mach_vm_protect, nullptr, Preamble_mach_vm_protect)      \
-  MACRO(rand, RR_ScalarRval)                                     \
-  MACRO(realpath,                                                \
-        RR_SaveRvalHadErrorZero<RR_Compose<RR_CStringRval,       \
-                                           RR_WriteOptionalBufferFixedSize<1, PATH_MAX>>>) \
-  MACRO(realpath$DARWIN_EXTSN,                                   \
-        RR_SaveRvalHadErrorZero<RR_Compose<RR_CStringRval,       \
-                                           RR_WriteOptionalBufferFixedSize<1, PATH_MAX>>>) \
-  /* By passing through events when initializing the sandbox, we ensure both */ \
-  /* that we actually initialize the process sandbox while replaying as well as */ \
-  /* while recording, and that any activity in these calls does not interfere */ \
-  /* with the replay. */                                         \
-  MACRO(sandbox_init, nullptr, Preamble_PassThrough)             \
-  MACRO(sandbox_init_with_parameters, nullptr, Preamble_PassThrough) \
-  /* Make sure events are passed through here so that replaying processes can */ \
-  /* inspect their own threads. */                               \
-  MACRO(task_threads, nullptr, Preamble_PassThrough)             \
-  MACRO(vm_copy, nullptr, Preamble_vm_copy)                      \
-  MACRO(vm_purgable_control, nullptr, Preamble_vm_purgable_control) \
-  MACRO(tzset)                                                   \
-  /* NSPR functions */                                           \
-  MACRO(PL_NewHashTable, nullptr, Preamble_PL_NewHashTable)      \
-  MACRO(PL_HashTableDestroy, nullptr, Preamble_PL_HashTableDestroy) \
-  /* Objective C functions */                                    \
-  MACRO(class_getClassMethod, RR_ScalarRval)                     \
-  MACRO(class_getInstanceMethod, RR_ScalarRval)                  \
-  MACRO(method_exchangeImplementations)                          \
-  MACRO(objc_autoreleasePoolPop)                                 \
-  MACRO(objc_autoreleasePoolPush, RR_ScalarRval)                 \
-  MACRO(objc_msgSend, RR_objc_msgSend, Preamble_objc_msgSend,    \
-        Middleman_objc_msgSend, MiddlemanPreamble_objc_msgSend)  \
-  /* Cocoa functions */                                          \
-  MACRO(AcquireFirstMatchingEventInQueue, RR_ScalarRval)         \
-  MACRO(CFArrayAppendValue)                                      \
-  MACRO(CFArrayCreate, RR_ScalarRval, nullptr, Middleman_CFArrayCreate) \
-  MACRO(CFArrayGetCount, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CFArrayGetValueAtIndex, RR_ScalarRval, nullptr, Middleman_CFArrayGetValueAtIndex) \
-  MACRO(CFArrayRemoveValueAtIndex)                               \
-  MACRO(CFAttributedStringCreate, RR_ScalarRval, nullptr,        \
-        Middleman_Compose<Middleman_CFTypeArg<1>, Middleman_CFTypeArg<2>, Middleman_CreateCFTypeRval>) \
-  MACRO(CFBundleCopyExecutableURL, RR_ScalarRval)                \
-  MACRO(CFBundleCopyInfoDictionaryForURL, RR_ScalarRval)         \
-  MACRO(CFBundleCreate, RR_ScalarRval)                           \
-  MACRO(CFBundleGetBundleWithIdentifier, RR_ScalarRval)          \
-  MACRO(CFBundleGetDataPointerForName, nullptr, Preamble_VetoIfNotPassedThrough<0>) \
-  MACRO(CFBundleGetFunctionPointerForName, nullptr, Preamble_VetoIfNotPassedThrough<0>) \
-  MACRO(CFBundleGetIdentifier, RR_ScalarRval)                    \
-  MACRO(CFBundleGetInfoDictionary, RR_ScalarRval)                \
-  MACRO(CFBundleGetMainBundle, RR_ScalarRval)                    \
-  MACRO(CFBundleGetValueForInfoDictionaryKey, RR_ScalarRval)     \
-  MACRO(CFDataGetBytePtr, RR_CFDataGetBytePtr, nullptr, Middleman_CFDataGetBytePtr) \
-  MACRO(CFDataGetLength, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CFDateFormatterCreate, RR_ScalarRval)                    \
-  MACRO(CFDateFormatterGetFormat, RR_ScalarRval)                 \
-  MACRO(CFDictionaryAddValue, nullptr, nullptr,                  \
-        Middleman_Compose<Middleman_UpdateCFTypeArg<0>,          \
-                          Middleman_CFTypeArg<1>,                \
-                          Middleman_CFTypeArg<2>>)               \
-  MACRO(CFDictionaryCreate, RR_ScalarRval, nullptr, Middleman_CFDictionaryCreate) \
-  MACRO(CFDictionaryCreateMutable, RR_ScalarRval, nullptr, Middleman_CreateCFTypeRval) \
-  MACRO(CFDictionaryCreateMutableCopy, RR_ScalarRval, nullptr,   \
-        Middleman_Compose<Middleman_CFTypeArg<2>, Middleman_CreateCFTypeRval>) \
-  MACRO(CFDictionaryGetValue, RR_ScalarRval, nullptr,            \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CFTypeRval>) \
-  MACRO(CFDictionaryGetValueIfPresent,                           \
-        RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<2, sizeof(const void*)>>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_CFTypeArg<1>,                \
-                          Middleman_CFTypeOutputArg<2>>)         \
-  MACRO(CFDictionaryReplaceValue, nullptr, nullptr,              \
-        Middleman_Compose<Middleman_UpdateCFTypeArg<0>,          \
-                          Middleman_CFTypeArg<1>,                \
-                          Middleman_CFTypeArg<2>>)               \
-  MACRO(CFEqual, RR_ScalarRval, nullptr,                         \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>>) \
-  MACRO(CFGetTypeID, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CFLocaleCopyCurrent, RR_ScalarRval)                      \
-  MACRO(CFLocaleCopyPreferredLanguages, RR_ScalarRval)           \
-  MACRO(CFLocaleCreate, RR_ScalarRval)                           \
-  MACRO(CFLocaleGetIdentifier, RR_ScalarRval)                    \
-  MACRO(CFNotificationCenterAddObserver, nullptr, Preamble_CFNotificationCenterAddObserver) \
-  MACRO(CFNotificationCenterGetLocalCenter, RR_ScalarRval)       \
-  MACRO(CFNotificationCenterRemoveObserver)                      \
-  MACRO(CFNumberCreate, RR_ScalarRval, nullptr, Middleman_CFNumberCreate) \
-  MACRO(CFNumberGetValue, RR_Compose<RR_ScalarRval, RR_CFNumberGetValue>, nullptr, \
-        Middleman_CFNumberGetValue)                              \
-  MACRO(CFNumberIsFloatType, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CFPreferencesAppValueIsForced, RR_ScalarRval)            \
-  MACRO(CFPreferencesCopyAppValue, RR_ScalarRval)                \
-  MACRO(CFPreferencesCopyValue, RR_ScalarRval)                   \
-  MACRO(CFPropertyListCreateFromXMLData, RR_ScalarRval)          \
-  MACRO(CFPropertyListCreateWithStream, RR_ScalarRval)           \
-  MACRO(CFReadStreamClose)                                       \
-  MACRO(CFReadStreamCreateWithFile, RR_ScalarRval)               \
-  MACRO(CFReadStreamOpen, RR_ScalarRval)                         \
-  /* Don't handle release/retain calls explicitly in the middleman, all resources */ \
-  /* will be cleaned up when its calls are reset. */             \
-  MACRO(CFRelease, RR_ScalarRval, nullptr, nullptr, Preamble_Veto<0>) \
-  MACRO(CFRetain, RR_ScalarRval, nullptr, nullptr, MiddlemanPreamble_CFRetain) \
-  MACRO(CFRunLoopAddSource)                                      \
-  MACRO(CFRunLoopGetCurrent, RR_ScalarRval)                      \
-  MACRO(CFRunLoopRemoveSource)                                   \
-  MACRO(CFRunLoopSourceCreate, RR_ScalarRval, Preamble_CFRunLoopSourceCreate) \
-  MACRO(CFRunLoopSourceInvalidate)                               \
-  MACRO(CFRunLoopSourceSignal)                                   \
-  MACRO(CFRunLoopWakeUp)                                         \
-  MACRO(CFStringAppendCharacters)                                \
-  MACRO(CFStringCompare, RR_ScalarRval, nullptr,                 \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>>) \
-  MACRO(CFStringCreateArrayBySeparatingStrings, RR_ScalarRval)   \
-  MACRO(CFStringCreateMutable, RR_ScalarRval)                    \
-  MACRO(CFStringCreateWithBytes, RR_ScalarRval, nullptr,         \
-        Middleman_Compose<Middleman_Buffer<1, 2>, Middleman_CreateCFTypeRval>) \
-  MACRO(CFStringCreateWithBytesNoCopy, RR_ScalarRval)            \
-  MACRO(CFStringCreateWithCharactersNoCopy, RR_ScalarRval, nullptr, \
-        Middleman_Compose<Middleman_Buffer<1, 2, UniChar>, Middleman_CreateCFTypeRval>) \
-  MACRO(CFStringCreateWithCString, RR_ScalarRval)                \
-  MACRO(CFStringCreateWithFormat, RR_ScalarRval)                 \
-  /* Argument indexes are off by one here as the CFRange argument uses two slots. */ \
-  MACRO(CFStringGetBytes, RR_Compose<                            \
-                            RR_ScalarRval,                       \
-                            RR_WriteOptionalBuffer<6, 7>,        \
-                            RR_WriteOptionalBufferFixedSize<8, sizeof(CFIndex)>>) \
-  /* Argument indexes are off by one here as the CFRange argument uses two slots. */ \
-  /* We also need to specify the argument register with the range's length here. */ \
-  MACRO(CFStringGetCharacters, RR_WriteBuffer<3, 2, UniChar>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_WriteBuffer<3, 2, UniChar>>) \
-  MACRO(CFStringGetCString, RR_Compose<RR_ScalarRval, RR_WriteBuffer<1, 2>>) \
-  MACRO(CFStringGetCStringPtr, nullptr, Preamble_VetoIfNotPassedThrough<0>) \
-  MACRO(CFStringGetIntValue, RR_ScalarRval)                      \
-  MACRO(CFStringGetLength, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CFStringGetMaximumSizeForEncoding, RR_ScalarRval)        \
-  MACRO(CFStringHasPrefix, RR_ScalarRval)                        \
-  MACRO(CFStringTokenizerAdvanceToNextToken, RR_ScalarRval)      \
-  MACRO(CFStringTokenizerCreate, RR_ScalarRval)                  \
-  MACRO(CFStringTokenizerGetCurrentTokenRange, RR_ComplexScalarRval) \
-  MACRO(CFURLCreateFromFileSystemRepresentation, RR_ScalarRval)  \
-  MACRO(CFURLCreateFromFSRef, RR_ScalarRval)                     \
-  MACRO(CFURLCreateWithFileSystemPath, RR_ScalarRval)            \
-  MACRO(CFURLCreateWithString, RR_ScalarRval)                    \
-  MACRO(CFURLGetFileSystemRepresentation, RR_Compose<RR_ScalarRval, RR_WriteBuffer<2, 3>>) \
-  MACRO(CFURLGetFSRef, RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<1, sizeof(FSRef)>>) \
-  MACRO(CFUUIDCreate, RR_ScalarRval, nullptr, Middleman_CreateCFTypeRval) \
-  MACRO(CFUUIDCreateString, RR_ScalarRval)                       \
-  MACRO(CFUUIDGetUUIDBytes, RR_ComplexScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CGAffineTransformConcat, RR_OversizeRval<sizeof(CGAffineTransform)>) \
-  MACRO(CGBitmapContextCreateImage, RR_ScalarRval)               \
-  MACRO(CGBitmapContextCreateWithData,                           \
-        RR_Compose<RR_ScalarRval, RR_CGBitmapContextCreateWithData>, nullptr, \
-        Middleman_CGBitmapContextCreateWithData)                 \
-  MACRO(CGBitmapContextGetBytesPerRow, RR_ScalarRval)            \
-  MACRO(CGBitmapContextGetHeight, RR_ScalarRval)                 \
-  MACRO(CGBitmapContextGetWidth, RR_ScalarRval)                  \
-  MACRO(CGColorRelease, RR_ScalarRval)                           \
-  MACRO(CGColorSpaceCopyICCProfile, RR_ScalarRval)               \
-  MACRO(CGColorSpaceCreateDeviceGray, RR_ScalarRval, nullptr, Middleman_CreateCFTypeRval) \
-  MACRO(CGColorSpaceCreateDeviceRGB, RR_ScalarRval, nullptr, Middleman_CreateCFTypeRval) \
-  MACRO(CGColorSpaceCreatePattern, RR_ScalarRval)                \
-  MACRO(CGColorSpaceRelease, RR_ScalarRval, nullptr, nullptr, Preamble_Veto<0>) \
-  MACRO(CGContextBeginTransparencyLayerWithRect)                 \
-  MACRO(CGContextClipToRects, RR_ScalarRval, nullptr,            \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_Buffer<1, 2, CGRect>>) \
-  MACRO(CGContextConcatCTM, nullptr, nullptr,                    \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_StackArgumentData<sizeof(CGAffineTransform)>>) \
-  MACRO(CGContextDrawImage, RR_FlushCGContext<0>)                \
-  MACRO(CGContextEndTransparencyLayer)                           \
-  MACRO(CGContextFillRect, RR_FlushCGContext<0>, nullptr,        \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_StackArgumentData<sizeof(CGRect)>, \
-                          Middleman_FlushCGContext<0>>)          \
-  MACRO(CGContextGetClipBoundingBox, RR_OversizeRval<sizeof(CGRect)>) \
-  MACRO(CGContextGetCTM, RR_OversizeRval<sizeof(CGAffineTransform)>) \
-  MACRO(CGContextGetType, RR_ScalarRval)                         \
-  MACRO(CGContextGetUserSpaceToDeviceSpaceTransform, RR_OversizeRval<sizeof(CGAffineTransform)>) \
-  MACRO(CGContextRestoreGState, nullptr, Preamble_CGContextRestoreGState, \
-        Middleman_UpdateCFTypeArg<0>)                            \
-  MACRO(CGContextSaveGState, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGContextSetAllowsFontSubpixelPositioning, nullptr, nullptr, \
-        Middleman_UpdateCFTypeArg<0>)                            \
-  MACRO(CGContextSetAllowsFontSubpixelQuantization, nullptr, nullptr, \
-        Middleman_UpdateCFTypeArg<0>)                            \
-  MACRO(CGContextSetAlpha, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGContextSetBaseCTM, nullptr, nullptr,                   \
-        Middleman_Compose<Middleman_UpdateCFTypeArg<0>,          \
-                          Middleman_StackArgumentData<sizeof(CGAffineTransform)>>) \
-  MACRO(CGContextSetCTM, nullptr, nullptr,                       \
-        Middleman_Compose<Middleman_UpdateCFTypeArg<0>,          \
-                          Middleman_StackArgumentData<sizeof(CGAffineTransform)>>) \
-  MACRO(CGContextSetGrayFillColor, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGContextSetRGBFillColor)                                \
-  MACRO(CGContextSetShouldAntialias, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGContextSetShouldSmoothFonts, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGContextSetShouldSubpixelPositionFonts, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGContextSetShouldSubpixelQuantizeFonts, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGContextSetTextDrawingMode, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGContextSetTextMatrix, nullptr, nullptr,                \
-        Middleman_Compose<Middleman_UpdateCFTypeArg<0>,          \
-                          Middleman_StackArgumentData<sizeof(CGAffineTransform)>>) \
-  MACRO(CGContextScaleCTM, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGContextTranslateCTM, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
-  MACRO(CGDataProviderCreateWithData, RR_Compose<RR_ScalarRval, RR_CGDataProviderCreateWithData>, \
-        nullptr, Middleman_CGDataProviderCreateWithData)         \
-  MACRO(CGDataProviderRelease, nullptr, nullptr, nullptr, Preamble_Veto<0>) \
-  MACRO(CGDisplayCopyColorSpace, RR_ScalarRval)                  \
-  MACRO(CGDisplayIOServicePort, RR_ScalarRval)                   \
-  MACRO(CGEventSourceCounterForEventType, RR_ScalarRval)         \
-  MACRO(CGFontCopyTableForTag, RR_ScalarRval, nullptr,           \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CGFontCopyTableTags, RR_ScalarRval, nullptr,             \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CGFontCopyVariations, RR_ScalarRval, nullptr,            \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CGFontCreateCopyWithVariations, RR_ScalarRval, nullptr,  \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_CFTypeArg<1>,                \
-                          Middleman_CreateCFTypeRval>)           \
-  MACRO(CGFontCreateWithDataProvider, RR_ScalarRval, nullptr,    \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CGFontCreateWithFontName, RR_ScalarRval, nullptr,        \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CGFontCreateWithPlatformFont, RR_ScalarRval)             \
-  MACRO(CGFontGetAscent, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CGFontGetCapHeight, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CGFontGetDescent, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CGFontGetFontBBox, RR_OversizeRval<sizeof(CGRect)>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<1>, Middleman_OversizeRval<sizeof(CGRect)>>) \
-  MACRO(CGFontGetGlyphAdvances, RR_Compose<RR_ScalarRval, RR_WriteBuffer<3, 2, int>>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_Buffer<1, 2, CGGlyph>,       \
-                          Middleman_WriteBuffer<3, 2, int>>)     \
-  MACRO(CGFontGetGlyphBBoxes, RR_Compose<RR_ScalarRval, RR_WriteBuffer<3, 2, CGRect>>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_Buffer<1, 2, CGGlyph>,       \
-                          Middleman_WriteBuffer<3, 2, CGRect>>)  \
-  MACRO(CGFontGetGlyphPath, RR_ScalarRval)                       \
-  MACRO(CGFontGetLeading, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CGFontGetUnitsPerEm, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CGFontGetXHeight, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CGImageGetHeight, RR_ScalarRval)                         \
-  MACRO(CGImageGetWidth, RR_ScalarRval)                          \
-  MACRO(CGImageRelease, RR_ScalarRval)                           \
-  MACRO(CGMainDisplayID, RR_ScalarRval)                          \
-  MACRO(CGPathAddPath)                                           \
-  MACRO(CGPathApply, nullptr, Preamble_CGPathApply)              \
-  MACRO(CGPathContainsPoint, RR_ScalarRval)                      \
-  MACRO(CGPathCreateMutable, RR_ScalarRval)                      \
-  MACRO(CGPathGetBoundingBox, RR_OversizeRval<sizeof(CGRect)>)   \
-  MACRO(CGPathGetCurrentPoint, RR_ComplexFloatRval)              \
-  MACRO(CGPathIsEmpty, RR_ScalarRval)                            \
-  MACRO(CGSSetDebugOptions, RR_ScalarRval)                       \
-  MACRO(CGSShutdownServerConnections)                            \
-  MACRO(CTFontCopyFamilyName, RR_ScalarRval, nullptr,            \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontCopyFeatures, RR_ScalarRval, nullptr,              \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontCopyFontDescriptor, RR_ScalarRval, nullptr,        \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontCopyGraphicsFont, RR_ScalarRval, nullptr,          \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontCopyTable, RR_ScalarRval, nullptr,                 \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontCopyVariationAxes, RR_ScalarRval, nullptr,         \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontCreateForString, RR_ScalarRval, nullptr,           \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontCreatePathForGlyph, RR_ScalarRval, nullptr,        \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_BufferFixedSize<2, sizeof(CGAffineTransform)>, \
-                          Middleman_CreateCFTypeRval>)           \
-  MACRO(CTFontCreateWithFontDescriptor, RR_ScalarRval, nullptr,  \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_BufferFixedSize<1, sizeof(CGAffineTransform)>, \
-                          Middleman_CreateCFTypeRval>)                 \
-  MACRO(CTFontCreateWithGraphicsFont, RR_ScalarRval, nullptr,    \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_BufferFixedSize<1, sizeof(CGAffineTransform)>, \
-                          Middleman_CFTypeArg<2>,                \
-                          Middleman_CreateCFTypeRval>)                 \
-  MACRO(CTFontCreateWithName, RR_ScalarRval, nullptr,            \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_BufferFixedSize<1, sizeof(CGAffineTransform)>, \
-                          Middleman_CreateCFTypeRval>)                 \
-  MACRO(CTFontDescriptorCopyAttribute, RR_ScalarRval, nullptr,   \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontDescriptorCreateCopyWithAttributes, RR_ScalarRval, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontDescriptorCreateMatchingFontDescriptors, RR_ScalarRval, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontDescriptorCreateWithAttributes, RR_ScalarRval, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTFontDrawGlyphs, RR_FlushCGContext<4>, nullptr,         \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_CFTypeArg<4>,                \
-                          Middleman_Buffer<1, 3, CGGlyph>,       \
-                          Middleman_Buffer<2, 3, CGPoint>,       \
-                          Middleman_FlushCGContext<4>>)          \
-  MACRO(CTFontGetAdvancesForGlyphs,                              \
-        RR_Compose<RR_FloatRval, RR_WriteOptionalBuffer<3, 4, CGSize>>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_Buffer<2, 4, CGGlyph>,       \
-                          Middleman_WriteBuffer<3, 4, CGSize>>)  \
-  MACRO(CTFontGetAscent, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>)   \
-  MACRO(CTFontGetBoundingBox, RR_OversizeRval<sizeof(CGRect)>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<1>, Middleman_OversizeRval<sizeof(CGRect)>>) \
-  MACRO(CTFontGetBoundingRectsForGlyphs,                         \
-        /* Argument indexes here are off by one due to the oversize rval. */ \
-        RR_Compose<RR_OversizeRval<sizeof(CGRect)>,              \
-                   RR_WriteOptionalBuffer<4, 5, CGRect>>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<1>,                \
-                          Middleman_Buffer<3, 5, CGGlyph>,       \
-                          Middleman_OversizeRval<sizeof(CGRect)>, \
-                          Middleman_WriteBuffer<4, 5, CGRect>>)  \
-  MACRO(CTFontGetCapHeight, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontGetDescent, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontGetGlyphCount, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontGetGlyphsForCharacters,                            \
-        RR_Compose<RR_ScalarRval, RR_WriteBuffer<2, 3, CGGlyph>>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_Buffer<1, 3, UniChar>,       \
-                          Middleman_WriteBuffer<2, 3, CGGlyph>>) \
-  MACRO(CTFontGetLeading, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontGetSize, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontGetSymbolicTraits, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontGetUnderlinePosition, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontGetUnderlineThickness, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontGetUnitsPerEm, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontGetXHeight, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTFontManagerCopyAvailableFontFamilyNames, RR_ScalarRval) \
-  MACRO(CTFontManagerRegisterFontsForURLs, RR_ScalarRval)        \
-  MACRO(CTFontManagerSetAutoActivationSetting)                   \
-  MACRO(CTLineCreateWithAttributedString, RR_ScalarRval, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
-  MACRO(CTLineGetGlyphRuns, RR_ScalarRval, nullptr,              \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeRval>) \
-  MACRO(CTRunGetAttributes, RR_ScalarRval, nullptr,              \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeRval>) \
-  MACRO(CTRunGetGlyphCount, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  MACRO(CTRunGetGlyphsPtr, RR_CTRunGetElements<CGGlyph, CTRunGetGlyphs>, nullptr, \
-        Middleman_CTRunGetElements<CGGlyph, CTRunGetGlyphs>)     \
-  MACRO(CTRunGetPositionsPtr, RR_CTRunGetElements<CGPoint, CTRunGetPositions>, nullptr, \
-        Middleman_CTRunGetElements<CGPoint, CTRunGetPositions>)  \
-  MACRO(CTRunGetStringIndicesPtr, RR_CTRunGetElements<CFIndex, CTRunGetStringIndices>, nullptr, \
-        Middleman_CTRunGetElements<CFIndex, CTRunGetStringIndices>) \
-  MACRO(CTRunGetStringRange, RR_ComplexScalarRval, nullptr, Middleman_CFTypeArg<0>) \
-  /* Argument indexes are off by one here as the CFRange argument uses two slots. */ \
-  MACRO(CTRunGetTypographicBounds,                               \
-        RR_Compose<RR_FloatRval,                                 \
-                   RR_WriteOptionalBufferFixedSize<3, sizeof(CGFloat)>, \
-                   RR_WriteOptionalBufferFixedSize<4, sizeof(CGFloat)>, \
-                   RR_WriteOptionalBufferFixedSize<5, sizeof(CGFloat)>>, nullptr, \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_WriteBufferFixedSize<3, sizeof(CGFloat)>, \
-                          Middleman_WriteBufferFixedSize<4, sizeof(CGFloat)>, \
-                          Middleman_WriteBufferFixedSize<5, sizeof(CGFloat)>>) \
-  MACRO(CUIDraw, nullptr, nullptr,                               \
-        Middleman_Compose<Middleman_CFTypeArg<0>,                \
-                          Middleman_CFTypeArg<1>,                \
-                          Middleman_CFTypeArg<2>,                \
-                          Middleman_StackArgumentData<sizeof(CGRect)>>) \
-  MACRO(FSCompareFSRefs, RR_ScalarRval)                          \
-  MACRO(FSGetVolumeInfo, RR_Compose<                             \
-                           RR_ScalarRval,                        \
-                           RR_WriteBufferFixedSize<5, sizeof(HFSUniStr255)>, \
-                           RR_WriteBufferFixedSize<6, sizeof(FSRef)>>) \
-  MACRO(FSFindFolder, RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<3, sizeof(FSRef)>>) \
-  MACRO(Gestalt, RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<1, sizeof(SInt32)>>) \
-  MACRO(GetEventClass, RR_ScalarRval)                            \
-  MACRO(GetCurrentEventQueue, RR_ScalarRval)                     \
-  MACRO(GetCurrentProcess,                                       \
-        RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(ProcessSerialNumber)>>) \
-  MACRO(GetEventAttributes, RR_ScalarRval)                       \
-  MACRO(GetEventDispatcherTarget, RR_ScalarRval)                 \
-  MACRO(GetEventKind, RR_ScalarRval)                             \
-  MACRO(HIThemeDrawButton, RR_ScalarRval)                        \
-  MACRO(HIThemeDrawFrame, RR_ScalarRval)                         \
-  MACRO(HIThemeDrawGroupBox, RR_ScalarRval)                      \
-  MACRO(HIThemeDrawGrowBox, RR_ScalarRval)                       \
-  MACRO(HIThemeDrawMenuBackground, RR_ScalarRval)                \
-  MACRO(HIThemeDrawMenuItem, RR_ScalarRval)                      \
-  MACRO(HIThemeDrawMenuSeparator, RR_ScalarRval)                 \
-  MACRO(HIThemeDrawSeparator, RR_ScalarRval)                     \
-  MACRO(HIThemeDrawTabPane, RR_ScalarRval)                       \
-  MACRO(HIThemeDrawTrack, RR_ScalarRval)                         \
-  MACRO(HIThemeGetGrowBoxBounds,                                 \
-        RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<2, sizeof(HIRect)>>) \
-  MACRO(HIThemeSetFill, RR_ScalarRval)                           \
-  MACRO(IORegistryEntrySearchCFProperty, RR_ScalarRval)          \
-  MACRO(LSCopyAllHandlersForURLScheme, RR_ScalarRval)            \
-  MACRO(LSCopyApplicationForMIMEType,                            \
-        RR_Compose<RR_ScalarRval, RR_WriteOptionalBufferFixedSize<2, sizeof(CFURLRef)>>) \
-  MACRO(LSCopyItemAttribute,                                     \
-        RR_Compose<RR_ScalarRval, RR_WriteOptionalBufferFixedSize<3, sizeof(CFTypeRef)>>) \
-  MACRO(LSCopyKindStringForMIMEType,                             \
-        RR_Compose<RR_ScalarRval, RR_WriteOptionalBufferFixedSize<1, sizeof(CFStringRef)>>) \
-  MACRO(LSGetApplicationForInfo, RR_Compose<                     \
-                                   RR_ScalarRval,                \
-                                   RR_WriteOptionalBufferFixedSize<4, sizeof(FSRef)>, \
-                                   RR_WriteOptionalBufferFixedSize<5, sizeof(CFURLRef)>>) \
-  MACRO(LSGetApplicationForURL, RR_Compose<                      \
-                                   RR_ScalarRval,                \
-                                   RR_WriteOptionalBufferFixedSize<2, sizeof(FSRef)>, \
-                                   RR_WriteOptionalBufferFixedSize<3, sizeof(CFURLRef)>>) \
-  MACRO(NSClassFromString, RR_ScalarRval, nullptr,               \
-        Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeRval>) \
-  MACRO(NSRectFill)                                              \
-  MACRO(NSSearchPathForDirectoriesInDomains, RR_ScalarRval)      \
-  MACRO(NSSetFocusRingStyle, RR_ScalarRval)                      \
-  MACRO(NSTemporaryDirectory, RR_ScalarRval)                     \
-  MACRO(OSSpinLockLock, nullptr, Preamble_OSSpinLockLock)        \
-  MACRO(ReleaseEvent, RR_ScalarRval)                             \
-  MACRO(RemoveEventFromQueue, RR_ScalarRval)                     \
-  MACRO(RetainEvent, RR_ScalarRval)                              \
-  MACRO(SCDynamicStoreCopyProxies, RR_ScalarRval)                \
-  MACRO(SCDynamicStoreCreate, RR_ScalarRval)                     \
-  MACRO(SCDynamicStoreCreateRunLoopSource, RR_ScalarRval)        \
-  MACRO(SCDynamicStoreKeyCreateProxies, RR_ScalarRval)           \
-  MACRO(SCDynamicStoreSetNotificationKeys, RR_ScalarRval)        \
-  MACRO(SendEventToEventTarget, RR_ScalarRval)                   \
-  /* These are not public APIs, but other redirected functions may be aliases for */ \
-  /* these which are dynamically installed on the first call in a way that our */ \
-  /* redirection mechanism doesn't completely account for. */    \
-  MACRO(SLDisplayCopyColorSpace, RR_ScalarRval)                  \
-  MACRO(SLDisplayIOServicePort, RR_ScalarRval)                   \
-  MACRO(SLEventSourceCounterForEventType, RR_ScalarRval)         \
-  MACRO(SLMainDisplayID, RR_ScalarRval)                          \
-  MACRO(SLSSetDenyWindowServerConnections, RR_ScalarRval)        \
-  MACRO(SLSShutdownServerConnections)
+///////////////////////////////////////////////////////////////////////////////
+// Original functions
+///////////////////////////////////////////////////////////////////////////////
 
-#define MAKE_CALL_EVENT(aName, ...)  CallEvent_ ##aName ,
+// Specify all the redirections for which the original function (with its
+// normal non-redirected semantics) is needed.
+#define FOR_EACH_ORIGINAL_FUNCTION(MACRO)                               \
+  MACRO(__workq_kernreturn)                                             \
+  MACRO(CFDataGetLength)                                                \
+  MACRO(CGPathApply)                                                    \
+  MACRO(close)                                                          \
+  MACRO(lseek)                                                          \
+  MACRO(mach_absolute_time)                                             \
+  MACRO(mmap)                                                           \
+  MACRO(mprotect)                                                       \
+  MACRO(munmap)                                                         \
+  MACRO(objc_msgSend)                                                   \
+  MACRO(open)                                                           \
+  MACRO(OSSpinLockLock)                                                 \
+  MACRO(pipe)                                                           \
+  MACRO(PL_HashTableDestroy)                                            \
+  MACRO(pthread_cond_wait)                                              \
+  MACRO(pthread_cond_timedwait)                                         \
+  MACRO(pthread_cond_timedwait_relative_np)                             \
+  MACRO(pthread_create)                                                 \
+  MACRO(pthread_mutex_destroy)                                          \
+  MACRO(pthread_mutex_init)                                             \
+  MACRO(pthread_mutex_lock)                                             \
+  MACRO(pthread_mutex_trylock)                                          \
+  MACRO(pthread_mutex_unlock)                                           \
+  MACRO(read)                                                           \
+  MACRO(start_wqthread)                                                 \
+  MACRO(write)
 
-enum CallEvent {                                \
-  FOR_EACH_REDIRECTION(MAKE_CALL_EVENT)         \
-  CallEvent_Count                               \
-};
+#define DECLARE_ORIGINAL_FUNCTION(aName)        \
+  static void* gOriginal_ ##aName;
 
-#undef MAKE_CALL_EVENT
+  FOR_EACH_ORIGINAL_FUNCTION(DECLARE_ORIGINAL_FUNCTION)
+
+#undef DECLARE_ORIGINAL_FUNCTION
 
 ///////////////////////////////////////////////////////////////////////////////
 // Callbacks
 ///////////////////////////////////////////////////////////////////////////////
 
 enum CallbackEvent {
   CallbackEvent_CFRunLoopPerformCallBack,
   CallbackEvent_CGPathApplierFunction
@@ -733,40 +177,54 @@ struct CFConstantString {
   char* mData;
   size_t mLength;
 };
 
 // Capture an Objective C or CoreFoundation input to a call, which may come
 // either from another middleman call, or from static data in the replaying
 // process.
 static void
-Middleman_ObjCInput(MiddlemanCallContext& aCx, id* aThingPtr)
+MM_ObjCInput(MiddlemanCallContext& aCx, id* aThingPtr)
 {
   MOZ_RELEASE_ASSERT(aCx.AccessPreface());
 
-  if (Middleman_SystemInput(aCx, (const void**) aThingPtr)) {
+  if (MM_SystemInput(aCx, (const void**) aThingPtr)) {
     // This value came from a previous middleman call.
     return;
   }
 
   MOZ_RELEASE_ASSERT(aCx.AccessInput());
 
   if (aCx.mPhase == MiddlemanCallPhase::ReplayInput) {
     // Try to determine where this object came from.
 
     // List of the Objective C classes which messages might be sent to directly.
     static const char* gStaticClasses[] = {
-      "NSAutoreleasePool",
+      // Standard classes.
+      "NSBezierPath",
+      "NSButtonCell",
       "NSColor",
+      "NSComboBoxCell",
       "NSDictionary",
+      "NSGraphicsContext",
       "NSFont",
       "NSFontManager",
+      "NSLevelIndicatorCell",
       "NSNumber",
+      "NSPopUpButtonCell",
+      "NSProgressBarCell",
       "NSString",
       "NSWindow",
+
+      // Gecko defined classes.
+      "CellDrawView",
+      "CheckboxCell",
+      "RadioButtonCell",
+      "SearchFieldCellWithFocusRing",
+      "ToolbarSearchFieldCellWithFocusRing",
     };
 
     // Watch for messages sent to particular classes.
     for (const char* className : gStaticClasses) {
       Class cls = objc_lookUpClass(className);
       if (cls == (Class) *aThingPtr) {
         aCx.WriteInputScalar((size_t) ObjCInputKind::StaticClass);
         size_t len = strlen(className) + 1;
@@ -817,28 +275,28 @@ Middleman_ObjCInput(MiddlemanCallContext
   }
   default:
     MOZ_CRASH();
   }
 }
 
 template <size_t Argument>
 static void
-Middleman_CFTypeArg(MiddlemanCallContext& aCx)
+MM_CFTypeArg(MiddlemanCallContext& aCx)
 {
   if (aCx.AccessPreface()) {
     auto& object = aCx.mArguments->Arg<Argument, id>();
-    Middleman_ObjCInput(aCx, &object);
+    MM_ObjCInput(aCx, &object);
   }
 }
 
 static void
-Middleman_CFTypeOutput(MiddlemanCallContext& aCx, CFTypeRef* aOutput, bool aOwnsReference)
+MM_CFTypeOutput(MiddlemanCallContext& aCx, CFTypeRef* aOutput, bool aOwnsReference)
 {
-  Middleman_SystemOutput(aCx, (const void**) aOutput);
+  MM_SystemOutput(aCx, (const void**) aOutput);
 
   if (*aOutput) {
     switch (aCx.mPhase) {
     case MiddlemanCallPhase::MiddlemanOutput:
       if (!aOwnsReference) {
         CFRetain(*aOutput);
       }
       break;
@@ -848,60 +306,60 @@ Middleman_CFTypeOutput(MiddlemanCallCont
     default:
       break;
     }
   }
 }
 
 // For APIs using the 'Get' rule: no reference is held on the returned value.
 static void
-Middleman_CFTypeRval(MiddlemanCallContext& aCx)
+MM_CFTypeRval(MiddlemanCallContext& aCx)
 {
   auto& rval = aCx.mArguments->Rval<CFTypeRef>();
-  Middleman_CFTypeOutput(aCx, &rval, /* aOwnsReference = */ false);
+  MM_CFTypeOutput(aCx, &rval, /* aOwnsReference = */ false);
 }
 
 // For APIs using the 'Create' rule: a reference is held on the returned
 // value which must be released.
 static void
-Middleman_CreateCFTypeRval(MiddlemanCallContext& aCx)
+MM_CreateCFTypeRval(MiddlemanCallContext& aCx)
 {
   auto& rval = aCx.mArguments->Rval<CFTypeRef>();
-  Middleman_CFTypeOutput(aCx, &rval, /* aOwnsReference = */ true);
+  MM_CFTypeOutput(aCx, &rval, /* aOwnsReference = */ true);
 }
 
 template <size_t Argument>
 static void
-Middleman_CFTypeOutputArg(MiddlemanCallContext& aCx)
+MM_CFTypeOutputArg(MiddlemanCallContext& aCx)
 {
-  Middleman_WriteBufferFixedSize<Argument, sizeof(const void*)>(aCx);
+  MM_WriteBufferFixedSize<Argument, sizeof(const void*)>(aCx);
 
   auto arg = aCx.mArguments->Arg<Argument, const void**>();
-  Middleman_CFTypeOutput(aCx, arg, /* aOwnsReference = */ false);
+  MM_CFTypeOutput(aCx, arg, /* aOwnsReference = */ false);
 }
 
 // For APIs whose result will be released by the middleman's autorelease pool.
 static void
-Middleman_AutoreleaseCFTypeRval(MiddlemanCallContext& aCx)
+MM_AutoreleaseCFTypeRval(MiddlemanCallContext& aCx)
 {
   auto& rval = aCx.mArguments->Rval<const void*>();
-  Middleman_SystemOutput(aCx, &rval);
+  MM_SystemOutput(aCx, &rval);
 }
 
 // For functions which have an input CFType value and also have side effects on
 // that value, this associates the call with its own input value so that this
 // will be treated as a dependent for any future calls using the value.
 template <size_t Argument>
 static void
-Middleman_UpdateCFTypeArg(MiddlemanCallContext& aCx)
+MM_UpdateCFTypeArg(MiddlemanCallContext& aCx)
 {
   auto arg = aCx.mArguments->Arg<Argument, const void*>();
 
-  Middleman_CFTypeArg<Argument>(aCx);
-  Middleman_SystemOutput(aCx, &arg, /* aUpdating = */ true);
+  MM_CFTypeArg<Argument>(aCx);
+  MM_SystemOutput(aCx, &arg, /* aUpdating = */ true);
 }
 
 template <int Error = EAGAIN>
 static PreambleResult
 Preamble_SetError(CallArguments* aArguments)
 {
   aArguments->Rval<ssize_t>() = -1;
   errno = Error;
@@ -979,31 +437,31 @@ Preamble_mmap(CallArguments* aArguments)
 
   void* memory = nullptr;
   if ((flags & MAP_ANON) || (IsReplaying() && !AreThreadEventsPassedThrough())) {
     // Get an anonymous mapping for the result.
     if (flags & MAP_FIXED) {
       // For fixed allocations, make sure this memory region is mapped and zero.
       if (!HasSavedCheckpoint()) {
         // Make sure this memory region is writable.
-        OriginalCall(mprotect, int, address, size, PROT_READ | PROT_WRITE | PROT_EXEC);
+        CallFunction<int>(gOriginal_mprotect, address, size, PROT_READ | PROT_WRITE | PROT_EXEC);
       }
       memset(address, 0, size);
       memory = address;
     } else {
       memory = AllocateMemoryTryAddress(address, RoundupSizeToPageBoundary(size),
                                         MemoryKind::Tracked);
     }
   } else {
     // We have to call mmap itself, which can change memory protection flags
     // for memory that is already allocated. If we haven't saved a checkpoint
     // then this is no problem, but after saving a checkpoint we have to make
     // sure that protection flags are what we expect them to be.
     int newProt = HasSavedCheckpoint() ? (PROT_READ | PROT_EXEC) : prot;
-    memory = OriginalCall(mmap, void*, address, size, newProt, flags, fd, offset);
+    memory = CallFunction<void*>(gOriginal_mmap, address, size, newProt, flags, fd, offset);
 
     if (flags & MAP_FIXED) {
       MOZ_RELEASE_ASSERT(memory == address);
       RestoreWritableFixedMemory(memory, RoundupSizeToPageBoundary(size));
     } else if (memory && memory != (void*)-1) {
       RegisterAllocatedMemory(memory, RoundupSizeToPageBoundary(size), MemoryKind::Tracked);
     }
   }
@@ -1147,52 +605,52 @@ Preamble___workq_kernreturn(CallArgument
   // Busy-wait until initialization is complete.
   while (!gInitialized) {
     ThreadYield();
   }
 
   // Make sure we know this thread exists.
   Thread::Current();
 
-  RecordReplayInvokeCall(CallEvent___workq_kernreturn, aArguments);
+  RecordReplayInvokeCall(gOriginal___workq_kernreturn, aArguments);
   return PreambleResult::Veto;
 }
 
 static PreambleResult
 Preamble_start_wqthread(CallArguments* aArguments)
 {
   // When replaying we don't want system threads to run, but by the time we
   // initialize the record/replay system GCD has already started running.
   // Use this redirection to watch for new threads being spawned by GCD, and
   // suspend them immediately.
   if (IsReplaying()) {
     Thread::WaitForeverNoIdle();
   }
 
-  RecordReplayInvokeCall(CallEvent_start_wqthread, aArguments);
+  RecordReplayInvokeCall(gOriginal_start_wqthread, aArguments);
   return PreambleResult::Veto;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // pthreads redirections
 ///////////////////////////////////////////////////////////////////////////////
 
 static void
 DirectLockMutex(pthread_mutex_t* aMutex)
 {
   AutoPassThroughThreadEvents pt;
-  ssize_t rv = OriginalCall(pthread_mutex_lock, ssize_t, aMutex);
+  ssize_t rv = CallFunction<ssize_t>(gOriginal_pthread_mutex_lock, aMutex);
   MOZ_RELEASE_ASSERT(rv == 0);
 }
 
 static void
 DirectUnlockMutex(pthread_mutex_t* aMutex)
 {
   AutoPassThroughThreadEvents pt;
-  ssize_t rv = OriginalCall(pthread_mutex_unlock, ssize_t, aMutex);
+  ssize_t rv = CallFunction<ssize_t>(gOriginal_pthread_mutex_unlock, aMutex);
   MOZ_RELEASE_ASSERT(rv == 0);
 }
 
 // Handle a redirection which releases a mutex, waits in some way for a cvar,
 // and reacquires the mutex before returning.
 static ssize_t
 WaitForCvar(pthread_mutex_t* aMutex, pthread_cond_t* aCond, bool aRecordReturnValue,
             const std::function<ssize_t()>& aCallback)
@@ -1241,43 +699,43 @@ WaitForCvar(pthread_mutex_t* aMutex, pth
 
 static PreambleResult
 Preamble_pthread_cond_wait(CallArguments* aArguments)
 {
   auto& cond = aArguments->Arg<0, pthread_cond_t*>();
   auto& mutex = aArguments->Arg<1, pthread_mutex_t*>();
   aArguments->Rval<ssize_t>() =
     WaitForCvar(mutex, cond, false,
-                [=]() { return OriginalCall(pthread_cond_wait, ssize_t, cond, mutex); });
+                [=]() { return CallFunction<ssize_t>(gOriginal_pthread_cond_wait, cond, mutex); });
   return PreambleResult::Veto;
 }
 
 static PreambleResult
 Preamble_pthread_cond_timedwait(CallArguments* aArguments)
 {
   auto& cond = aArguments->Arg<0, pthread_cond_t*>();
   auto& mutex = aArguments->Arg<1, pthread_mutex_t*>();
   auto& timeout = aArguments->Arg<2, timespec*>();
   aArguments->Rval<ssize_t>() =
     WaitForCvar(mutex, cond, true,
-                [=]() { return OriginalCall(pthread_cond_timedwait, ssize_t,
-                                            cond, mutex, timeout); });
+                [=]() { return CallFunction<ssize_t>(gOriginal_pthread_cond_timedwait,
+                                                     cond, mutex, timeout); });
   return PreambleResult::Veto;
 }
 
 static PreambleResult
 Preamble_pthread_cond_timedwait_relative_np(CallArguments* aArguments)
 {
   auto& cond = aArguments->Arg<0, pthread_cond_t*>();
   auto& mutex = aArguments->Arg<1, pthread_mutex_t*>();
   auto& timeout = aArguments->Arg<2, timespec*>();
   aArguments->Rval<ssize_t>() =
     WaitForCvar(mutex, cond, true,
-                [=]() { return OriginalCall(pthread_cond_timedwait_relative_np, ssize_t,
-                                            cond, mutex, timeout); });
+                [=]() { return CallFunction<ssize_t>(gOriginal_pthread_cond_timedwait_relative_np,
+                                                     cond, mutex, timeout); });
   return PreambleResult::Veto;
 }
 
 static PreambleResult
 Preamble_pthread_create(CallArguments* aArguments)
 {
   if (AreThreadEventsPassedThrough()) {
     return PreambleResult::Redirect;
@@ -1324,45 +782,45 @@ Preamble_pthread_join(CallArguments* aAr
 
 static PreambleResult
 Preamble_pthread_mutex_init(CallArguments* aArguments)
 {
   auto& mutex = aArguments->Arg<0, pthread_mutex_t*>();
   auto& attr = aArguments->Arg<1, pthread_mutexattr_t*>();
 
   Lock::New(mutex);
-  aArguments->Rval<ssize_t>() = OriginalCall(pthread_mutex_init, ssize_t, mutex, attr);
+  aArguments->Rval<ssize_t>() = CallFunction<ssize_t>(gOriginal_pthread_mutex_init, mutex, attr);
   return PreambleResult::Veto;
 }
 
 static PreambleResult
 Preamble_pthread_mutex_destroy(CallArguments* aArguments)
 {
   auto& mutex = aArguments->Arg<0, pthread_mutex_t*>();
 
   Lock::Destroy(mutex);
-  aArguments->Rval<ssize_t>() = OriginalCall(pthread_mutex_destroy, ssize_t, mutex);
+  aArguments->Rval<ssize_t>() = CallFunction<ssize_t>(gOriginal_pthread_mutex_destroy, mutex);
   return PreambleResult::Veto;
 }
 
 static PreambleResult
 Preamble_pthread_mutex_lock(CallArguments* aArguments)
 {
   auto& mutex = aArguments->Arg<0, pthread_mutex_t*>();
 
   Lock* lock = Lock::Find(mutex);
   if (!lock) {
     AutoEnsurePassThroughThreadEventsUseStackPointer pt;
-    aArguments->Rval<ssize_t>() = OriginalCall(pthread_mutex_lock, ssize_t, mutex);
+    aArguments->Rval<ssize_t>() = CallFunction<ssize_t>(gOriginal_pthread_mutex_lock, mutex);
     return PreambleResult::Veto;
   }
   ssize_t rv = 0;
   if (IsRecording()) {
     AutoPassThroughThreadEvents pt;
-    rv = OriginalCall(pthread_mutex_lock, ssize_t, mutex);
+    rv = CallFunction<ssize_t>(gOriginal_pthread_mutex_lock, mutex);
   }
   rv = RecordReplayValue(rv);
   MOZ_RELEASE_ASSERT(rv == 0 || rv == EDEADLK);
   if (rv == 0) {
     lock->Enter();
     if (IsReplaying()) {
       DirectLockMutex(mutex);
     }
@@ -1374,23 +832,23 @@ Preamble_pthread_mutex_lock(CallArgument
 static PreambleResult
 Preamble_pthread_mutex_trylock(CallArguments* aArguments)
 {
   auto& mutex = aArguments->Arg<0, pthread_mutex_t*>();
 
   Lock* lock = Lock::Find(mutex);
   if (!lock) {
     AutoEnsurePassThroughThreadEvents pt;
-    aArguments->Rval<ssize_t>() = OriginalCall(pthread_mutex_trylock, ssize_t, mutex);
+    aArguments->Rval<ssize_t>() = CallFunction<ssize_t>(gOriginal_pthread_mutex_trylock, mutex);
     return PreambleResult::Veto;
   }
   ssize_t rv = 0;
   if (IsRecording()) {
     AutoPassThroughThreadEvents pt;
-    rv = OriginalCall(pthread_mutex_trylock, ssize_t, mutex);
+    rv = CallFunction<ssize_t>(gOriginal_pthread_mutex_trylock, mutex);
   }
   rv = RecordReplayValue(rv);
   MOZ_RELEASE_ASSERT(rv == 0 || rv == EBUSY);
   if (rv == 0) {
     lock->Enter();
     if (IsReplaying()) {
       DirectLockMutex(mutex);
     }
@@ -1402,17 +860,17 @@ Preamble_pthread_mutex_trylock(CallArgum
 static PreambleResult
 Preamble_pthread_mutex_unlock(CallArguments* aArguments)
 {
   auto& mutex = aArguments->Arg<0, pthread_mutex_t*>();
 
   Lock* lock = Lock::Find(mutex);
   if (!lock) {
     AutoEnsurePassThroughThreadEventsUseStackPointer pt;
-    aArguments->Rval<ssize_t>() = OriginalCall(pthread_mutex_unlock, ssize_t, mutex);
+    aArguments->Rval<ssize_t>() = CallFunction<ssize_t>(gOriginal_pthread_mutex_unlock, mutex);
     return PreambleResult::Veto;
   }
   lock->Exit();
   DirectUnlockMutex(mutex);
   aArguments->Rval<ssize_t>() = 0;
   return PreambleResult::Veto;
 }
 
@@ -1443,16 +901,19 @@ Preamble_getenv(CallArguments* aArgument
 
   // The JPEG library can fetch configuration information from the environment
   // in a way that can run non-deterministically on different threads.
   if (strncmp(env, "JSIMD_", 6) == 0) {
     aArguments->Rval<char*>() = nullptr;
     return PreambleResult::Veto;
   }
 
+  // Include the environment variable being checked in an assertion, to make it
+  // easier to debug recording mismatches involving getenv.
+  RecordReplayAssert("getenv %s", env);
   return PreambleResult::Redirect;
 }
 
 static struct tm gGlobalTM;
 
 // localtime behaves the same as localtime_r, except it is not reentrant.
 // For simplicity, define this in terms of localtime_r.
 static PreambleResult
@@ -1471,17 +932,17 @@ Preamble_gmtime(CallArguments* aArgument
 }
 
 static PreambleResult
 Preamble_mach_absolute_time(CallArguments* aArguments)
 {
   // This function might be called through OSSpinLock while setting gTlsThreadKey.
   Thread* thread = Thread::GetByStackPointer(&thread);
   if (!thread || thread->PassThroughEvents()) {
-    aArguments->Rval<uint64_t>() = OriginalCall(mach_absolute_time, uint64_t);
+    aArguments->Rval<uint64_t>() = CallFunction<uint64_t>(gOriginal_mach_absolute_time);
     return PreambleResult::Veto;
   }
   return PreambleResult::Redirect;
 }
 
 static PreambleResult
 Preamble_mach_vm_allocate(CallArguments* aArguments)
 {
@@ -1577,17 +1038,17 @@ Preamble_PL_NewHashTable(CallArguments* 
 }
 
 static PreambleResult
 Preamble_PL_HashTableDestroy(CallArguments* aArguments)
 {
   auto& table = aArguments->Arg<0, PLHashTable*>();
 
   void* priv = table->allocPriv;
-  OriginalCall(PL_HashTableDestroy, void, table);
+  CallFunction<void>(gOriginal_PL_HashTableDestroy, table);
   DestroyPLHashTableCallbacks(priv);
   return PreambleResult::Veto;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Objective C redirections
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -1612,17 +1073,17 @@ Preamble_objc_msgSend(CallArguments* aAr
     auto message = aArguments->Arg<1, const char*>();
 
     // Watch for some top level NSApplication messages that can cause Gecko
     // events to be processed.
     if (!strcmp(message, "run") ||
         !strcmp(message, "nextEventMatchingMask:untilDate:inMode:dequeue:"))
     {
       PassThroughThreadEventsAllowCallbacks([&]() {
-          RecordReplayInvokeCall(CallEvent_objc_msgSend, aArguments);
+          RecordReplayInvokeCall(gOriginal_objc_msgSend, aArguments);
         });
       RecordReplayBytes(&aArguments->Rval<size_t>(), sizeof(size_t));
       return PreambleResult::Veto;
     }
   }
   return PreambleResult::Redirect;
 }
 
@@ -1668,76 +1129,105 @@ RR_objc_msgSend(Stream& aEvents, CallArg
     }
     aEvents.RecordOrReplayBytes(rval, len + 1);
   }
 }
 
 static PreambleResult
 MiddlemanPreamble_objc_msgSend(CallArguments* aArguments)
 {
+  auto obj = aArguments->Arg<0, id>();
   auto message = aArguments->Arg<1, const char*>();
 
+  // Fake object value which allows null checks in the caller to pass.
+  static const size_t FakeId = 1;
+
   // Ignore uses of NSAutoreleasePool after diverging from the recording.
   // These are not performed in the middleman because the middleman has its
   // own autorelease pool, and because the middleman can process calls from
   // multiple threads which will cause these messages to behave differently.
-  if (!strcmp(message, "alloc") ||
+  // release messages are also ignored, as for CFRelease.
+  if ((!strcmp(message, "alloc") && obj == (id) objc_lookUpClass("NSAutoreleasePool")) ||
+      (!strcmp(message, "init") && obj == (id) FakeId) ||
       !strcmp(message, "drain") ||
-      !strcmp(message, "init") ||
       !strcmp(message, "release")) {
     // Fake a return value in case the caller null checks it.
     aArguments->Rval<size_t>() = 1;
     return PreambleResult::Veto;
   }
 
-  // Other messages will be handled by Middleman_objc_msgSend.
+  // Other messages will be handled by MM_objc_msgSend.
   return PreambleResult::Redirect;
 }
 
 static void
-Middleman_PerformSelector(MiddlemanCallContext& aCx)
+MM_PerformSelector(MiddlemanCallContext& aCx)
 {
-  Middleman_CString<2>(aCx);
-  Middleman_CFTypeArg<3>(aCx);
+  MM_CString<2>(aCx);
+  MM_CFTypeArg<3>(aCx);
 
   // The behavior of performSelector:withObject: varies depending on the
   // selector used, so use a whitelist here.
   if (aCx.mPhase == MiddlemanCallPhase::ReplayPreface) {
     auto str = aCx.mArguments->Arg<2, const char*>();
     if (strcmp(str, "appearanceNamed:")) {
       aCx.MarkAsFailed();
       return;
     }
   }
 
-  Middleman_AutoreleaseCFTypeRval(aCx);
+  MM_AutoreleaseCFTypeRval(aCx);
 }
 
 static void
-Middleman_DictionaryWithObjects(MiddlemanCallContext& aCx)
+MM_DictionaryWithObjectsAndKeys(MiddlemanCallContext& aCx)
 {
-  Middleman_Buffer<2, 4, const void*>(aCx);
-  Middleman_Buffer<3, 4, const void*>(aCx);
+  // Copy over all possible stack arguments.
+  MM_StackArgumentData<CallArguments::NumStackArguments * sizeof(size_t)>(aCx);
+
+  if (aCx.AccessPreface()) {
+    // Advance through the arguments until there is a null value. If there are
+    // too many arguments for the underlying CallArguments, we will safely
+    // crash when we hit their extent.
+    for (size_t i = 2;; i += 2) {
+      auto& value = aCx.mArguments->Arg<id>(i);
+      if (!value) {
+        break;
+      }
+      auto& key = aCx.mArguments->Arg<id>(i + 1);
+      MM_ObjCInput(aCx, &value);
+      MM_ObjCInput(aCx, &key);
+    }
+  }
+
+  MM_AutoreleaseCFTypeRval(aCx);
+}
+
+static void
+MM_DictionaryWithObjects(MiddlemanCallContext& aCx)
+{
+  MM_Buffer<2, 4, const void*>(aCx);
+  MM_Buffer<3, 4, const void*>(aCx);
 
   if (aCx.AccessPreface()) {
     auto objects = aCx.mArguments->Arg<2, const void**>();
     auto keys = aCx.mArguments->Arg<3, const void**>();
     auto count = aCx.mArguments->Arg<4, CFIndex>();
 
     for (CFIndex i = 0; i < count; i++) {
-      Middleman_ObjCInput(aCx, (id*) &objects[i]);
-      Middleman_ObjCInput(aCx, (id*) &keys[i]);
+      MM_ObjCInput(aCx, (id*) &objects[i]);
+      MM_ObjCInput(aCx, (id*) &keys[i]);
     }
   }
 
-  Middleman_AutoreleaseCFTypeRval(aCx);
+  MM_AutoreleaseCFTypeRval(aCx);
 }
 
 static void
-Middleman_NSStringGetCharacters(MiddlemanCallContext& aCx)
+MM_NSStringGetCharacters(MiddlemanCallContext& aCx)
 {
   auto string = aCx.mArguments->Arg<0, CFStringRef>();
   auto& buffer = aCx.mArguments->Arg<2, void*>();
 
   if (aCx.mPhase == MiddlemanCallPhase::MiddlemanInput) {
     size_t len = CFStringGetLength(string);
     buffer = aCx.AllocateBytes(len * sizeof(UniChar));
   }
@@ -1752,189 +1242,255 @@ Middleman_NSStringGetCharacters(Middlema
     aCx.ReadOrWriteOutputBytes(buffer, len * sizeof(UniChar));
   }
 }
 
 struct ObjCMessageInfo
 {
   const char* mMessage;
   MiddlemanCallFn mMiddlemanCall;
+  bool mUpdatesObject;
 };
 
 // All Objective C messages that can be called in the middleman, and hooks for
-// capturing any inputs and outputs other than the object and message.
+// capturing any inputs and outputs other than the object, message, and scalar
+// arguments / return values.
 static ObjCMessageInfo gObjCMiddlemanCallMessages[] = {
-  { "performSelector:withObject:", Middleman_PerformSelector },
-  { "respondsToSelector:", Middleman_CString<2> },
+  // Generic
+  { "alloc", MM_CreateCFTypeRval },
+  { "init", MM_AutoreleaseCFTypeRval },
+  { "performSelector:withObject:", MM_PerformSelector },
+  { "respondsToSelector:", MM_CString<2> },
+
+  // NSAppearance
+  { "_drawInRect:context:options:",
+    MM_Compose<MM_StackArgumentData<sizeof(CGRect)>, MM_CFTypeArg<2>, MM_CFTypeArg<3>> },
 
   // NSArray
   { "count" },
-  { "objectAtIndex:", Middleman_AutoreleaseCFTypeRval },
+  { "objectAtIndex:", MM_AutoreleaseCFTypeRval },
+
+  // NSBezierPath
+  { "addClip", MM_NoOp, true },
+  { "bezierPathWithRoundedRect:xRadius:yRadius:", MM_AutoreleaseCFTypeRval },
+
+  // NSCell
+  { "drawFocusRingMaskWithFrame:inView:",
+    MM_Compose<MM_CFTypeArg<2>, MM_StackArgumentData<sizeof(CGRect)>> },
+  { "drawWithFrame:inView:",
+    MM_Compose<MM_CFTypeArg<2>, MM_StackArgumentData<sizeof(CGRect)>> },
+  { "initTextCell:", MM_Compose<MM_CFTypeArg<2>, MM_AutoreleaseCFTypeRval> },
+  { "initTextCell:pullsDown:", MM_Compose<MM_CFTypeArg<2>, MM_AutoreleaseCFTypeRval> },
+  { "setAllowsMixedState:", MM_NoOp, true },
+  { "setBezeled:", MM_NoOp, true },
+  { "setBezelStyle:", MM_NoOp, true },
+  { "setButtonType:", MM_NoOp, true },
+  { "setControlSize:", MM_NoOp, true },
+  { "setControlTint:", MM_NoOp, true },
+  { "setCriticalValue:", MM_NoOp, true },
+  { "setDoubleValue:", MM_NoOp, true },
+  { "setEditable:", MM_NoOp, true },
+  { "setEnabled:", MM_NoOp, true },
+  { "setFocusRingType:", MM_NoOp, true },
+  { "setHighlighted:", MM_NoOp, true },
+  { "setHighlightsBy:", MM_NoOp, true },
+  { "setHorizontal:", MM_NoOp, true },
+  { "setIndeterminate:", MM_NoOp, true },
+  { "setMax:", MM_NoOp, true },
+  { "setMaxValue:", MM_NoOp, true },
+  { "setMinValue:", MM_NoOp, true },
+  { "setPlaceholderString:", MM_NoOp, true },
+  { "setPullsDown:", MM_NoOp, true },
+  { "setShowsFirstResponder:", MM_NoOp, true },
+  { "setState:", MM_NoOp, true },
+  { "setValue:", MM_NoOp, true },
+  { "setWarningValue:", MM_NoOp, true },
+  { "showsFirstResponder" },
 
   // NSColor
+  { "alphaComponent" },
+  { "colorWithDeviceRed:green:blue:alpha:",
+    MM_Compose<MM_StackArgumentData<sizeof(CGFloat)>, MM_AutoreleaseCFTypeRval> },
   { "currentControlTint" },
+  { "set", MM_NoOp, true },
 
   // NSDictionary
-  { "dictionaryWithObjects:forKeys:count:", Middleman_DictionaryWithObjects },
+  { "dictionaryWithObjectsAndKeys:", MM_DictionaryWithObjectsAndKeys },
+  { "dictionaryWithObjects:forKeys:count:", MM_DictionaryWithObjects },
+  { "mutableCopy", MM_AutoreleaseCFTypeRval },
+  { "setObject:forKey:", MM_Compose<MM_CFTypeArg<2>, MM_CFTypeArg<3>>, true },
 
   // NSFont
-  { "boldSystemFontOfSize:", Middleman_AutoreleaseCFTypeRval },
-  { "controlContentFontOfSize:", Middleman_AutoreleaseCFTypeRval },
-  { "familyName", Middleman_AutoreleaseCFTypeRval },
-  { "fontDescriptor", Middleman_AutoreleaseCFTypeRval },
-  { "menuBarFontOfSize:", Middleman_AutoreleaseCFTypeRval },
+  { "boldSystemFontOfSize:", MM_AutoreleaseCFTypeRval },
+  { "controlContentFontOfSize:", MM_AutoreleaseCFTypeRval },
+  { "familyName", MM_AutoreleaseCFTypeRval },
+  { "fontDescriptor", MM_AutoreleaseCFTypeRval },
+  { "menuBarFontOfSize:", MM_AutoreleaseCFTypeRval },
   { "pointSize" },
   { "smallSystemFontSize" },
-  { "systemFontOfSize:", Middleman_AutoreleaseCFTypeRval },
-  { "toolTipsFontOfSize:", Middleman_AutoreleaseCFTypeRval },
-  { "userFontOfSize:", Middleman_AutoreleaseCFTypeRval },
+  { "systemFontOfSize:", MM_AutoreleaseCFTypeRval },
+  { "toolTipsFontOfSize:", MM_AutoreleaseCFTypeRval },
+  { "userFontOfSize:", MM_AutoreleaseCFTypeRval },
 
   // NSFontManager
-  { "availableMembersOfFontFamily:", Middleman_Compose<Middleman_CFTypeArg<2>, Middleman_AutoreleaseCFTypeRval> },
-  { "sharedFontManager", Middleman_AutoreleaseCFTypeRval },
+  { "availableMembersOfFontFamily:", MM_Compose<MM_CFTypeArg<2>, MM_AutoreleaseCFTypeRval> },
+  { "sharedFontManager", MM_AutoreleaseCFTypeRval },
+
+  // NSGraphicsContext
+  { "currentContext", MM_AutoreleaseCFTypeRval },
+  { "graphicsContextWithGraphicsPort:flipped:",
+    MM_Compose<MM_CFTypeArg<2>, MM_AutoreleaseCFTypeRval> },
+  { "graphicsPort", MM_AutoreleaseCFTypeRval },
+  { "restoreGraphicsState" },
+  { "saveGraphicsState" },
+  { "setCurrentContext:", MM_CFTypeArg<2> },
 
   // NSNumber
-  { "numberWithBool:", Middleman_AutoreleaseCFTypeRval },
+  { "numberWithBool:", MM_AutoreleaseCFTypeRval },
   { "unsignedIntValue" },
 
   // NSString
-  { "getCharacters:", Middleman_NSStringGetCharacters },
-  { "hasSuffix:", Middleman_CFTypeArg<2> },
-  { "isEqualToString:", Middleman_CFTypeArg<2> },
+  { "getCharacters:", MM_NSStringGetCharacters },
+  { "hasSuffix:", MM_CFTypeArg<2> },
+  { "isEqualToString:", MM_CFTypeArg<2> },
   { "length" },
-  { "rangeOfString:options:", Middleman_CFTypeArg<2> },
+  { "rangeOfString:options:", MM_CFTypeArg<2> },
   { "stringWithCharacters:length:",
-    Middleman_Compose<Middleman_Buffer<2, 3, UniChar>, Middleman_AutoreleaseCFTypeRval> },
+    MM_Compose<MM_Buffer<2, 3, UniChar>, MM_AutoreleaseCFTypeRval> },
 
   // NSWindow
-  { "coreUIRenderer", Middleman_AutoreleaseCFTypeRval },
+  { "coreUIRenderer", MM_AutoreleaseCFTypeRval },
 
   // UIFontDescriptor
   { "symbolicTraits" },
 };
 
 static void
-Middleman_objc_msgSend(MiddlemanCallContext& aCx)
+MM_objc_msgSend(MiddlemanCallContext& aCx)
 {
-  auto& object = aCx.mArguments->Arg<0, id>();
   auto message = aCx.mArguments->Arg<1, const char*>();
 
   for (const ObjCMessageInfo& info : gObjCMiddlemanCallMessages) {
     if (!strcmp(info.mMessage, message)) {
-      if (aCx.AccessPreface()) {
-        Middleman_ObjCInput(aCx, &object);
+      if (info.mUpdatesObject) {
+        MM_UpdateCFTypeArg<0>(aCx);
+      } else {
+        MM_CFTypeArg<0>(aCx);
       }
       if (info.mMiddlemanCall && !aCx.mFailed) {
         info.mMiddlemanCall(aCx);
       }
+      if (child::CurrentRepaintCannotFail() && aCx.mFailed) {
+        child::ReportFatalError(Nothing(), "Middleman message failure: %s\n", message);
+      }
       return;
     }
   }
 
   if (aCx.mPhase == MiddlemanCallPhase::ReplayPreface) {
     aCx.MarkAsFailed();
+    if (child::CurrentRepaintCannotFail()) {
+      child::ReportFatalError(Nothing(), "Could not perform middleman message: %s\n", message);
+    }
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Cocoa redirections
 ///////////////////////////////////////////////////////////////////////////////
 
 static void
-Middleman_CFArrayCreate(MiddlemanCallContext& aCx)
+MM_CFArrayCreate(MiddlemanCallContext& aCx)
 {
-  Middleman_Buffer<1, 2, const void*>(aCx);
+  MM_Buffer<1, 2, const void*>(aCx);
 
   if (aCx.AccessPreface()) {
     auto values = aCx.mArguments->Arg<1, const void**>();
     auto numValues = aCx.mArguments->Arg<2, CFIndex>();
     auto& callbacks = aCx.mArguments->Arg<3, const CFArrayCallBacks*>();
 
     // For now we only support creating arrays with CFType elements.
     if (aCx.mPhase == MiddlemanCallPhase::MiddlemanInput) {
       callbacks = &kCFTypeArrayCallBacks;
     } else {
       MOZ_RELEASE_ASSERT(callbacks == &kCFTypeArrayCallBacks);
     }
 
     for (CFIndex i = 0; i < numValues; i++) {
-      Middleman_ObjCInput(aCx, (id*) &values[i]);
+      MM_ObjCInput(aCx, (id*) &values[i]);
     }
   }
 
-  Middleman_CreateCFTypeRval(aCx);
+  MM_CreateCFTypeRval(aCx);
 }
 
 static void
-Middleman_CFArrayGetValueAtIndex(MiddlemanCallContext& aCx)
+MM_CFArrayGetValueAtIndex(MiddlemanCallContext& aCx)
 {
-  Middleman_CFTypeArg<0>(aCx);
+  MM_CFTypeArg<0>(aCx);
 
   auto array = aCx.mArguments->Arg<0, id>();
 
   // We can't probe the array to see what callbacks it uses, so look at where
   // it came from to see whether its elements should be treated as CFTypes.
   MiddlemanCall* call = LookupMiddlemanCall(array);
   bool isCFTypeRval = false;
   if (call) {
-    switch (call->mCallId) {
-    case CallEvent_CTLineGetGlyphRuns:
-    case CallEvent_CTFontCopyVariationAxes:
-    case CallEvent_CTFontDescriptorCreateMatchingFontDescriptors:
+    const char* name = GetRedirection(call->mCallId).mName;
+    if (!strcmp(name, "CTLineGetGlyphRuns") ||
+        !strcmp(name, "CTFontCopyVariationAxes") ||
+        !strcmp(name, "CTFontDescriptorCreateMatchingFontDescriptors")) {
       isCFTypeRval = true;
-      break;
-    default:
-      break;
     }
   }
 
   if (isCFTypeRval) {
-    Middleman_CFTypeRval(aCx);
+    MM_CFTypeRval(aCx);
   }
 }
 
 static void
 RR_CFDataGetBytePtr(Stream& aEvents, CallArguments* aArguments, ErrorType* aError)
 {
   auto& rval = aArguments->Rval<UInt8*>();
 
   size_t len = 0;
   if (IsRecording()) {
-    len = OriginalCall(CFDataGetLength, size_t, aArguments->Arg<0, CFDataRef>());
+    len = CallFunction<size_t>(gOriginal_CFDataGetLength, aArguments->Arg<0, CFDataRef>());
   }
   aEvents.RecordOrReplayValue(&len);
   if (IsReplaying()) {
     rval = NewLeakyArray<UInt8>(len);
   }
   aEvents.RecordOrReplayBytes(rval, len);
 }
 
 static void
-Middleman_CFDataGetBytePtr(MiddlemanCallContext& aCx)
+MM_CFDataGetBytePtr(MiddlemanCallContext& aCx)
 {
-  Middleman_CFTypeArg<0>(aCx);
+  MM_CFTypeArg<0>(aCx);
 
   auto data = aCx.mArguments->Arg<0, CFDataRef>();
   auto& buffer = aCx.mArguments->Rval<void*>();
 
   if (aCx.AccessOutput()) {
     size_t len = (aCx.mPhase == MiddlemanCallPhase::MiddlemanOutput) ? CFDataGetLength(data) : 0;
     aCx.ReadOrWriteOutputBytes(&len, sizeof(len));
     if (aCx.mPhase == MiddlemanCallPhase::ReplayOutput) {
       buffer = aCx.AllocateBytes(len);
     }
     aCx.ReadOrWriteOutputBytes(buffer, len);
   }
 }
 
 static void
-Middleman_CFDictionaryCreate(MiddlemanCallContext& aCx)
+MM_CFDictionaryCreate(MiddlemanCallContext& aCx)
 {
-  Middleman_Buffer<1, 3, const void*>(aCx);
-  Middleman_Buffer<2, 3, const void*>(aCx);
+  MM_Buffer<1, 3, const void*>(aCx);
+  MM_Buffer<2, 3, const void*>(aCx);
 
   if (aCx.AccessPreface()) {
     auto keys = aCx.mArguments->Arg<1, const void**>();
     auto values = aCx.mArguments->Arg<2, const void**>();
     auto numValues = aCx.mArguments->Arg<3, CFIndex>();
     auto& keyCallbacks = aCx.mArguments->Arg<4, const CFDictionaryKeyCallBacks*>();
     auto& valueCallbacks = aCx.mArguments->Arg<5, const CFDictionaryValueCallBacks*>();
 
@@ -1943,22 +1499,22 @@ Middleman_CFDictionaryCreate(MiddlemanCa
       keyCallbacks = &kCFTypeDictionaryKeyCallBacks;
       valueCallbacks = &kCFTypeDictionaryValueCallBacks;
     } else {
       MOZ_RELEASE_ASSERT(keyCallbacks == &kCFTypeDictionaryKeyCallBacks);
       MOZ_RELEASE_ASSERT(valueCallbacks == &kCFTypeDictionaryValueCallBacks);
     }
 
     for (CFIndex i = 0; i < numValues; i++) {
-      Middleman_ObjCInput(aCx, (id*) &keys[i]);
-      Middleman_ObjCInput(aCx, (id*) &values[i]);
+      MM_ObjCInput(aCx, (id*) &keys[i]);
+      MM_ObjCInput(aCx, (id*) &values[i]);
     }
   }
 
-  Middleman_CreateCFTypeRval(aCx);
+  MM_CreateCFTypeRval(aCx);
 }
 
 static void DummyCFNotificationCallback(CFNotificationCenterRef aCenter, void* aObserver,
                                         CFStringRef aName, const void* aObject,
                                         CFDictionaryRef aUserInfo)
 {
   // FIXME
   //MOZ_CRASH();
@@ -1994,41 +1550,41 @@ CFNumberTypeBytes(CFNumberType aType)
   case kCFNumberCFIndexType: return sizeof(CFIndex);
   case kCFNumberNSIntegerType: return sizeof(long);
   case kCFNumberCGFloatType: return sizeof(CGFloat);
   default: MOZ_CRASH();
   }
 }
 
 static void
-Middleman_CFNumberCreate(MiddlemanCallContext& aCx)
+MM_CFNumberCreate(MiddlemanCallContext& aCx)
 {
   if (aCx.AccessPreface()) {
     auto numberType = aCx.mArguments->Arg<1, CFNumberType>();
     auto& valuePtr = aCx.mArguments->Arg<2, void*>();
     aCx.ReadOrWritePrefaceBuffer(&valuePtr, CFNumberTypeBytes(numberType));
   }
 
-  Middleman_CreateCFTypeRval(aCx);
+  MM_CreateCFTypeRval(aCx);
 }
 
 static void
 RR_CFNumberGetValue(Stream& aEvents, CallArguments* aArguments, ErrorType* aError)
 {
   auto& type = aArguments->Arg<1, CFNumberType>();
   auto& value = aArguments->Arg<2, void*>();
 
   aEvents.CheckInput(type);
   aEvents.RecordOrReplayBytes(value, CFNumberTypeBytes(type));
 }
 
 static void
-Middleman_CFNumberGetValue(MiddlemanCallContext& aCx)
+MM_CFNumberGetValue(MiddlemanCallContext& aCx)
 {
-  Middleman_CFTypeArg<0>(aCx);
+  MM_CFTypeArg<0>(aCx);
 
   auto& buffer = aCx.mArguments->Arg<2, void*>();
   auto type = aCx.mArguments->Arg<1, CFNumberType>();
   aCx.ReadOrWriteOutputBuffer(&buffer, CFNumberTypeBytes(type));
 }
 
 static PreambleResult
 MiddlemanPreamble_CFRetain(CallArguments* aArguments)
@@ -2073,30 +1629,30 @@ RR_CGBitmapContextCreateWithData(Stream&
 {
   auto& data = aArguments->Arg<0, void*>();
   auto& height = aArguments->Arg<2, size_t>();
   auto& bytesPerRow = aArguments->Arg<4, size_t>();
   auto& rval = aArguments->Rval<CGContextRef>();
 
   MOZ_RELEASE_ASSERT(Thread::CurrentIsMainThread());
 
-  // When replaying, Middleman_CGBitmapContextCreateWithData will take care of
+  // When replaying, MM_CGBitmapContextCreateWithData will take care of
   // updating gContextData with the right context pointer (after being mangled
-  // in Middleman_SystemOutput).
+  // in MM_SystemOutput).
   if (IsRecording()) {
     gContextData.emplaceBack(rval, data, height * bytesPerRow);
   }
 }
 
 static void
-Middleman_CGBitmapContextCreateWithData(MiddlemanCallContext& aCx)
+MM_CGBitmapContextCreateWithData(MiddlemanCallContext& aCx)
 {
-  Middleman_CFTypeArg<5>(aCx);
-  Middleman_StackArgumentData<3 * sizeof(size_t)>(aCx);
-  Middleman_CreateCFTypeRval(aCx);
+  MM_CFTypeArg<5>(aCx);
+  MM_StackArgumentData<3 * sizeof(size_t)>(aCx);
+  MM_CreateCFTypeRval(aCx);
 
   auto& data = aCx.mArguments->Arg<0, void*>();
   auto height = aCx.mArguments->Arg<2, size_t>();
   auto bytesPerRow = aCx.mArguments->Arg<4, size_t>();
   auto rval = aCx.mArguments->Rval<CGContextRef>();
 
   if (aCx.mPhase == MiddlemanCallPhase::MiddlemanInput) {
     data = aCx.AllocateBytes(height * bytesPerRow);
@@ -2120,42 +1676,42 @@ RR_FlushCGContext(Stream& aEvents, CallA
       return;
     }
   }
   MOZ_CRASH("RR_FlushCGContext");
 }
 
 template <size_t ContextArgument>
 static void
-Middleman_FlushCGContext(MiddlemanCallContext& aCx)
+MM_FlushCGContext(MiddlemanCallContext& aCx)
 {
   auto context = aCx.mArguments->Arg<ContextArgument, CGContextRef>();
 
   // Update the contents of the target buffer in the middleman process to match
   // the current contents in the replaying process.
   if (aCx.AccessInput()) {
     for (int i = gContextData.length() - 1; i >= 0; i--) {
       if (context == gContextData[i].mContext) {
         aCx.ReadOrWriteInputBytes(gContextData[i].mData, gContextData[i].mDataSize);
         return;
       }
     }
-    MOZ_CRASH("Middleman_FlushCGContext");
+    MOZ_CRASH("MM_FlushCGContext");
   }
 
   // After performing the call, the buffer in the replaying process is updated
   // to match any data written by the middleman.
   if (aCx.AccessOutput()) {
     for (int i = gContextData.length() - 1; i >= 0; i--) {
       if (context == gContextData[i].mContext) {
         aCx.ReadOrWriteOutputBytes(gContextData[i].mData, gContextData[i].mDataSize);
         return;
       }
     }
-    MOZ_CRASH("Middleman_FlushCGContext");
+    MOZ_CRASH("MM_FlushCGContext");
   }
 }
 
 static PreambleResult
 Preamble_CGContextRestoreGState(CallArguments* aArguments)
 {
   return IsRecording() ? PreambleResult::PassThrough : PreambleResult::Veto;
 }
@@ -2176,20 +1732,20 @@ RR_CGDataProviderCreateWithData(Stream& 
 
 static void
 ReleaseDataCallback(void*, const void* aData, size_t)
 {
   free((void*) aData);
 }
 
 static void
-Middleman_CGDataProviderCreateWithData(MiddlemanCallContext& aCx)
+MM_CGDataProviderCreateWithData(MiddlemanCallContext& aCx)
 {
-  Middleman_Buffer<1, 2>(aCx);
-  Middleman_CreateCFTypeRval(aCx);
+  MM_Buffer<1, 2>(aCx);
+  MM_CreateCFTypeRval(aCx);
 
   auto& info = aCx.mArguments->Arg<0, void*>();
   auto& data = aCx.mArguments->Arg<1, const void*>();
   auto& size = aCx.mArguments->Arg<2, size_t>();
   auto& releaseData = aCx.mArguments->Arg<3, CGDataProviderReleaseDataCallback>();
 
   // Make a copy of the data that won't be released the next time middleman
   // calls are reset, in case CoreGraphics decides to hang onto the data
@@ -2217,17 +1773,17 @@ Preamble_CGPathApply(CallArguments* aArg
   auto& path = aArguments->Arg<0, CGPathRef>();
   auto& data = aArguments->Arg<1, void*>();
   auto& function = aArguments->Arg<2, CGPathApplierFunction>();
 
   RegisterCallbackData(BitwiseCast<void*>(function));
   RegisterCallbackData(data);
   PassThroughThreadEventsAllowCallbacks([&]() {
       CallbackWrapperData wrapperData(function, data);
-      OriginalCall(CGPathApply, void, path, &wrapperData, CGPathApplierFunctionWrapper);
+      CallFunction<void>(gOriginal_CGPathApply, path, &wrapperData, CGPathApplierFunctionWrapper);
     });
   RemoveCallbackData(data);
 
   return PreambleResult::Veto;
 }
 
 // Note: We only redirect CTRunGetGlyphsPtr, not CTRunGetGlyphs. The latter may
 // be implemented with a loop that jumps back into the code we overwrite with a
@@ -2256,19 +1812,19 @@ RR_CTRunGetElements(Stream& aEvents, Cal
   if (IsReplaying()) {
     rval = NewLeakyArray<ElemType>(count);
   }
   aEvents.RecordOrReplayBytes(rval, count * sizeof(ElemType));
 }
 
 template <typename ElemType, void (*GetElemsFn)(CTRunRef, CFRange, ElemType*)>
 static void
-Middleman_CTRunGetElements(MiddlemanCallContext& aCx)
+MM_CTRunGetElements(MiddlemanCallContext& aCx)
 {
-  Middleman_CFTypeArg<0>(aCx);
+  MM_CFTypeArg<0>(aCx);
 
   if (aCx.AccessOutput()) {
     auto run = aCx.mArguments->Arg<0, CTRunRef>();
     auto& rval = aCx.mArguments->Rval<ElemType*>();
 
     size_t count = 0;
     if (IsMiddleman()) {
       count = CTRunGetGlyphCount(run);
@@ -2290,142 +1846,932 @@ Preamble_OSSpinLockLock(CallArguments* a
 {
   auto& lock = aArguments->Arg<0, OSSpinLock*>();
 
   // These spin locks never need to be recorded, but they are used by malloc
   // and can end up calling other recorded functions like mach_absolute_time,
   // so make sure events are passed through here. Note that we don't have to
   // redirect OSSpinLockUnlock, as it doesn't have these issues.
   AutoEnsurePassThroughThreadEventsUseStackPointer pt;
-  OriginalCall(OSSpinLockLock, void, lock);
+  CallFunction<void>(gOriginal_OSSpinLockLock, lock);
 
   return PreambleResult::Veto;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// System Redirections
+///////////////////////////////////////////////////////////////////////////////
+
+// System APIs that are redirected, and associated callbacks.
+struct SystemRedirection
+{
+  const char* mName;
+  SaveOutputFn mSaveOutput;
+  PreambleFn mPreamble;
+  MiddlemanCallFn mMiddlemanCall;
+  PreambleFn mMiddlemanPreamble;
+};
+
+// Specify every library function that is redirected by looking up its address
+// with dlsym.
+static SystemRedirection gSystemRedirections[] = {
+  /////////////////////////////////////////////////////////////////////////////
+  // System call wrappers
+  /////////////////////////////////////////////////////////////////////////////
+
+  { "kevent",
+    RR_SaveRvalHadErrorNegative<RR_WriteBuffer<3, 4, struct kevent>>,
+    nullptr, nullptr, Preamble_WaitForever },
+  { "kevent64", RR_SaveRvalHadErrorNegative<RR_WriteBuffer<3, 4, struct kevent64_s>> },
+  { "mprotect", nullptr, Preamble_mprotect },
+  { "mmap", nullptr, Preamble_mmap },
+  { "munmap", nullptr, Preamble_munmap },
+  { "read",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>>,
+    nullptr, nullptr, Preamble_SetError<EIO> },
+  { "__read_nocancel", RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>> },
+  { "pread", RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>> },
+  { "write", RR_SaveRvalHadErrorNegative, nullptr, nullptr, MiddlemanPreamble_write },
+  { "__write_nocancel", RR_SaveRvalHadErrorNegative },
+  { "open", RR_SaveRvalHadErrorNegative },
+  { "__open_nocancel", RR_SaveRvalHadErrorNegative },
+  { "recv", RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>> },
+  { "recvmsg", RR_SaveRvalHadErrorNegative<RR_recvmsg>, nullptr, nullptr, Preamble_WaitForever },
+  { "sendmsg", RR_SaveRvalHadErrorNegative, nullptr, nullptr, MiddlemanPreamble_sendmsg },
+  { "shm_open", RR_SaveRvalHadErrorNegative },
+  { "socket", RR_SaveRvalHadErrorNegative },
+  { "kqueue", RR_SaveRvalHadErrorNegative },
+  { "pipe",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<0, 2 * sizeof(int)>>,
+    nullptr, nullptr, Preamble_SetError },
+  { "close", RR_SaveRvalHadErrorNegative, nullptr, nullptr, Preamble_Veto<0> },
+  { "__close_nocancel", RR_SaveRvalHadErrorNegative },
+  { "mkdir", RR_SaveRvalHadErrorNegative },
+  { "dup", RR_SaveRvalHadErrorNegative },
+  { "access", RR_SaveRvalHadErrorNegative, nullptr, nullptr, Preamble_SetError<EACCES> },
+  { "lseek", RR_SaveRvalHadErrorNegative },
+  { "socketpair", RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<3, 2 * sizeof(int)>> },
+  { "fileport_makeport", RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(size_t)>> },
+  { "getsockopt", RR_SaveRvalHadErrorNegative<RR_getsockopt> },
+  { "gettimeofday",
+    RR_SaveRvalHadErrorNegative<
+      RR_Compose<RR_WriteOptionalBufferFixedSize<0, sizeof(struct timeval)>,
+                 RR_WriteOptionalBufferFixedSize<1, sizeof(struct timezone)>>>,
+    nullptr, nullptr, Preamble_PassThrough },
+  { "getuid", RR_ScalarRval },
+  { "geteuid", RR_ScalarRval },
+  { "getgid", RR_ScalarRval },
+  { "getegid", RR_ScalarRval },
+  { "issetugid", RR_ScalarRval },
+  { "__gettid", RR_ScalarRval },
+  { "getpid", nullptr, Preamble_getpid },
+  { "fcntl", RR_SaveRvalHadErrorNegative, Preamble_fcntl, nullptr, MiddlemanPreamble_fcntl },
+  { "getattrlist", RR_SaveRvalHadErrorNegative<RR_WriteBuffer<2, 3>> },
+  { "fstat$INODE64",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct stat)>>,
+    nullptr, nullptr, Preamble_SetError },
+  { "lstat$INODE64",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct stat)>>,
+    nullptr, nullptr, Preamble_SetError },
+  { "stat$INODE64",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct stat)>>,
+    nullptr, nullptr, Preamble_SetError },
+  { "statfs$INODE64",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct statfs)>>,
+    nullptr, nullptr, Preamble_SetError },
+  { "fstatfs$INODE64",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct statfs)>>,
+    nullptr, nullptr, Preamble_SetError },
+  { "readlink", RR_SaveRvalHadErrorNegative<RR_WriteBuffer<1, 2>> },
+  { "__getdirentries64",
+    RR_SaveRvalHadErrorNegative<
+      RR_Compose<RR_WriteBuffer<1, 2>,
+                 RR_WriteBufferFixedSize<3, sizeof(size_t)>>> },
+  { "getdirentriesattr",
+    RR_SaveRvalHadErrorNegative<
+      RR_Compose<RR_WriteBufferFixedSize<1, sizeof(struct attrlist)>,
+                 RR_WriteBuffer<2, 3>,
+                 RR_WriteBufferFixedSize<4, sizeof(size_t)>,
+                 RR_WriteBufferFixedSize<5, sizeof(size_t)>,
+                 RR_WriteBufferFixedSize<6, sizeof(size_t)>>> },
+  { "getrusage",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct rusage)>>,
+    nullptr, nullptr, Preamble_PassThrough },
+  { "__getrlimit",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct rlimit)>> },
+  { "__setrlimit", RR_SaveRvalHadErrorNegative },
+  { "sigprocmask",
+    RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(sigset_t)>>,
+    nullptr, nullptr, Preamble_PassThrough },
+  { "sigaltstack",
+    RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(stack_t)>> },
+  { "sigaction",
+    RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(struct sigaction)>> },
+  { "__pthread_sigmask",
+    RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(sigset_t)>> },
+  { "__fsgetpath", RR_SaveRvalHadErrorNegative<RR_WriteBuffer<0, 1>> },
+  { "__disable_threadsignal", nullptr, Preamble___disable_threadsignal },
+  { "__sysctl", RR_SaveRvalHadErrorNegative<RR___sysctl> },
+  { "__mac_syscall", RR_SaveRvalHadErrorNegative },
+  { "getaudit_addr",
+    RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<0, sizeof(auditinfo_addr_t)>> },
+  { "umask", RR_ScalarRval },
+  { "__select",
+    RR_SaveRvalHadErrorNegative<
+      RR_Compose<RR_WriteBufferFixedSize<1, sizeof(fd_set)>,
+                 RR_WriteBufferFixedSize<2, sizeof(fd_set)>,
+                 RR_WriteBufferFixedSize<3, sizeof(fd_set)>,
+                 RR_WriteOptionalBufferFixedSize<4, sizeof(timeval)>>>,
+    nullptr, nullptr, Preamble_WaitForever },
+  { "__process_policy", RR_SaveRvalHadErrorNegative },
+  { "__kdebug_trace", RR_SaveRvalHadErrorNegative },
+  { "guarded_kqueue_np", RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<0, sizeof(size_t)>> },
+  { "csops", RR_SaveRvalHadErrorNegative<RR_WriteBuffer<2, 3>> },
+  { "__getlogin", RR_SaveRvalHadErrorNegative<RR_WriteBuffer<0, 1>> },
+  { "__workq_kernreturn", nullptr, Preamble___workq_kernreturn },
+  { "start_wqthread", nullptr, Preamble_start_wqthread },
+
+  /////////////////////////////////////////////////////////////////////////////
+  // PThreads interfaces
+  /////////////////////////////////////////////////////////////////////////////
+
+  { "pthread_cond_wait", nullptr, Preamble_pthread_cond_wait },
+  { "pthread_cond_timedwait", nullptr, Preamble_pthread_cond_timedwait },
+  { "pthread_cond_timedwait_relative_np", nullptr, Preamble_pthread_cond_timedwait_relative_np },
+  { "pthread_create", nullptr, Preamble_pthread_create },
+  { "pthread_join", nullptr, Preamble_pthread_join },
+  { "pthread_mutex_init", nullptr, Preamble_pthread_mutex_init },
+  { "pthread_mutex_destroy", nullptr, Preamble_pthread_mutex_destroy },
+  { "pthread_mutex_lock", nullptr, Preamble_pthread_mutex_lock },
+  { "pthread_mutex_trylock", nullptr, Preamble_pthread_mutex_trylock },
+  { "pthread_mutex_unlock", nullptr, Preamble_pthread_mutex_unlock },
+
+  /////////////////////////////////////////////////////////////////////////////
+  // C library functions
+  /////////////////////////////////////////////////////////////////////////////
+
+  { "dlclose", nullptr, Preamble_Veto<0> },
+  { "dlopen", nullptr, Preamble_PassThrough },
+  { "dlsym", nullptr, Preamble_PassThrough },
+  { "fclose", RR_SaveRvalHadErrorNegative },
+  { "fopen", RR_SaveRvalHadErrorZero },
+  { "fread", RR_Compose<RR_ScalarRval, RR_fread> },
+  { "fseek", RR_SaveRvalHadErrorNegative },
+  { "ftell", RR_SaveRvalHadErrorNegative },
+  { "fwrite", RR_ScalarRval },
+  { "getenv", RR_CStringRval, Preamble_getenv, nullptr, Preamble_Veto<0> },
+  { "localtime_r",
+    RR_SaveRvalHadErrorZero<
+      RR_Compose<RR_WriteBufferFixedSize<1, sizeof(struct tm)>,
+                 RR_RvalIsArgument<1>>>,
+    nullptr, nullptr, Preamble_PassThrough },
+  { "gmtime_r",
+    RR_SaveRvalHadErrorZero<
+      RR_Compose<RR_WriteBufferFixedSize<1, sizeof(struct tm)>,
+                 RR_RvalIsArgument<1>>>,
+    nullptr, nullptr, Preamble_PassThrough },
+  { "localtime", nullptr, Preamble_localtime, nullptr, Preamble_PassThrough },
+  { "gmtime", nullptr, Preamble_gmtime, nullptr, Preamble_PassThrough },
+  { "mktime", RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(struct tm)>> },
+  { "setlocale", RR_CStringRval },
+  { "strftime", RR_Compose<RR_ScalarRval, RR_WriteBufferViaRval<0, 1, 1>> },
+  { "arc4random", RR_ScalarRval, nullptr, nullptr, Preamble_PassThrough },
+  { "mach_absolute_time",
+    RR_ScalarRval, Preamble_mach_absolute_time, nullptr, Preamble_PassThrough },
+  { "mach_msg",
+    RR_Compose<RR_ScalarRval, RR_WriteBuffer<0, 3>>, nullptr, nullptr, Preamble_WaitForever },
+  { "mach_timebase_info",
+    RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(mach_timebase_info_data_t)>> },
+  { "mach_vm_allocate", nullptr, Preamble_mach_vm_allocate },
+  { "mach_vm_deallocate", nullptr, Preamble_mach_vm_deallocate },
+  { "mach_vm_map", nullptr, Preamble_mach_vm_map },
+  { "mach_vm_protect", nullptr, Preamble_mach_vm_protect },
+  { "rand", RR_ScalarRval },
+  { "realpath",
+    RR_SaveRvalHadErrorZero<
+      RR_Compose<RR_CStringRval,
+                 RR_WriteOptionalBufferFixedSize<1, PATH_MAX>>> },
+  { "realpath$DARWIN_EXTSN",
+    RR_SaveRvalHadErrorZero<
+      RR_Compose<RR_CStringRval,
+                 RR_WriteOptionalBufferFixedSize<1, PATH_MAX>>> },
+
+  // By passing through events when initializing the sandbox, we ensure both
+  // that we actually initialize the process sandbox while replaying as well as
+  // while recording, and that any activity in these calls does not interfere
+  // with the replay.
+  { "sandbox_init", nullptr, Preamble_PassThrough },
+  { "sandbox_init_with_parameters", nullptr, Preamble_PassThrough },
+
+  // Make sure events are passed through here so that replaying processes can
+  // inspect their own threads.
+  { "task_threads", nullptr, Preamble_PassThrough },
+
+  { "vm_copy", nullptr, Preamble_vm_copy },
+  { "vm_purgable_control", nullptr, Preamble_vm_purgable_control },
+  { "tzset" },
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Gecko functions
+  /////////////////////////////////////////////////////////////////////////////
+
+  // These are defined in NSPR, but it is easier to just redirect them to
+  // change their behavior than to actually modify their code.
+  { "PL_NewHashTable", nullptr, Preamble_PL_NewHashTable },
+  { "PL_HashTableDestroy", nullptr, Preamble_PL_HashTableDestroy },
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Objective C functions
+  /////////////////////////////////////////////////////////////////////////////
+
+  { "class_getClassMethod", RR_ScalarRval },
+  { "class_getInstanceMethod", RR_ScalarRval },
+  { "method_exchangeImplementations" },
+  { "objc_autoreleasePoolPop" },
+  { "objc_autoreleasePoolPush", RR_ScalarRval },
+  { "objc_msgSend",
+    RR_objc_msgSend, Preamble_objc_msgSend, MM_objc_msgSend, MiddlemanPreamble_objc_msgSend },
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Cocoa and CoreFoundation library functions
+  /////////////////////////////////////////////////////////////////////////////
+
+  { "AcquireFirstMatchingEventInQueue", RR_ScalarRval },
+  { "CFArrayAppendValue" },
+  { "CFArrayCreate", RR_ScalarRval, nullptr, MM_CFArrayCreate },
+  { "CFArrayGetCount", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CFArrayGetValueAtIndex", RR_ScalarRval, nullptr, MM_CFArrayGetValueAtIndex },
+  { "CFArrayRemoveValueAtIndex" },
+  { "CFAttributedStringCreate",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_CFTypeArg<1>, MM_CFTypeArg<2>, MM_CreateCFTypeRval> },
+  { "CFBundleCopyExecutableURL", RR_ScalarRval },
+  { "CFBundleCopyInfoDictionaryForURL", RR_ScalarRval },
+  { "CFBundleCreate", RR_ScalarRval },
+  { "CFBundleGetBundleWithIdentifier", RR_ScalarRval },
+  { "CFBundleGetDataPointerForName", nullptr, Preamble_VetoIfNotPassedThrough<0> },
+  { "CFBundleGetFunctionPointerForName", nullptr, Preamble_VetoIfNotPassedThrough<0> },
+  { "CFBundleGetIdentifier", RR_ScalarRval },
+  { "CFBundleGetInfoDictionary", RR_ScalarRval },
+  { "CFBundleGetMainBundle", RR_ScalarRval },
+  { "CFBundleGetValueForInfoDictionaryKey", RR_ScalarRval },
+  { "CFDataGetBytePtr", RR_CFDataGetBytePtr, nullptr, MM_CFDataGetBytePtr },
+  { "CFDataGetLength", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CFDateFormatterCreate", RR_ScalarRval },
+  { "CFDateFormatterGetFormat", RR_ScalarRval },
+  { "CFDictionaryAddValue",
+    nullptr, nullptr, MM_Compose<MM_UpdateCFTypeArg<0>, MM_CFTypeArg<1>, MM_CFTypeArg<2>> },
+  { "CFDictionaryCreate", RR_ScalarRval, nullptr, MM_CFDictionaryCreate },
+  { "CFDictionaryCreateMutable", RR_ScalarRval, nullptr, MM_CreateCFTypeRval },
+  { "CFDictionaryCreateMutableCopy",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<2>, MM_CreateCFTypeRval> },
+  { "CFDictionaryGetValue",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>, MM_CFTypeRval> },
+  { "CFDictionaryGetValueIfPresent",
+    RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<2, sizeof(const void*)>>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>, MM_CFTypeOutputArg<2>> },
+  { "CFDictionaryReplaceValue",
+    nullptr, nullptr, MM_Compose<MM_UpdateCFTypeArg<0>, MM_CFTypeArg<1>, MM_CFTypeArg<2>> },
+  { "CFEqual", RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>> },
+  { "CFGetTypeID", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CFLocaleCopyCurrent", RR_ScalarRval },
+  { "CFLocaleCopyPreferredLanguages", RR_ScalarRval },
+  { "CFLocaleCreate", RR_ScalarRval },
+  { "CFLocaleGetIdentifier", RR_ScalarRval },
+  { "CFNotificationCenterAddObserver", nullptr, Preamble_CFNotificationCenterAddObserver },
+  { "CFNotificationCenterGetLocalCenter", RR_ScalarRval },
+  { "CFNotificationCenterRemoveObserver" },
+  { "CFNumberCreate", RR_ScalarRval, nullptr, MM_CFNumberCreate },
+  { "CFNumberGetValue",
+    RR_Compose<RR_ScalarRval, RR_CFNumberGetValue>, nullptr, MM_CFNumberGetValue },
+  { "CFNumberIsFloatType", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CFPreferencesAppValueIsForced", RR_ScalarRval },
+  { "CFPreferencesCopyAppValue", RR_ScalarRval },
+  { "CFPreferencesCopyValue", RR_ScalarRval },
+  { "CFPropertyListCreateFromXMLData", RR_ScalarRval },
+  { "CFPropertyListCreateWithStream", RR_ScalarRval },
+  { "CFReadStreamClose" },
+  { "CFReadStreamCreateWithFile", RR_ScalarRval },
+  { "CFReadStreamOpen", RR_ScalarRval },
+
+  // Don't handle release/retain calls explicitly in the middleman:
+  // all resources will be cleaned up when its calls are reset.
+  { "CFRelease", RR_ScalarRval, nullptr, nullptr, Preamble_Veto<0> },
+  { "CFRetain", RR_ScalarRval, nullptr, nullptr, MiddlemanPreamble_CFRetain },
+
+  { "CFRunLoopAddSource" },
+  { "CFRunLoopGetCurrent", RR_ScalarRval },
+  { "CFRunLoopRemoveSource" },
+  { "CFRunLoopSourceCreate", RR_ScalarRval, Preamble_CFRunLoopSourceCreate },
+  { "CFRunLoopSourceInvalidate" },
+  { "CFRunLoopSourceSignal" },
+  { "CFRunLoopWakeUp" },
+  { "CFStringAppendCharacters" },
+  { "CFStringCompare", RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>> },
+  { "CFStringCreateArrayBySeparatingStrings", RR_ScalarRval },
+  { "CFStringCreateMutable", RR_ScalarRval },
+  { "CFStringCreateWithBytes",
+    RR_ScalarRval, nullptr, MM_Compose<MM_Buffer<1, 2>, MM_CreateCFTypeRval> },
+  { "CFStringCreateWithBytesNoCopy", RR_ScalarRval },
+  { "CFStringCreateWithCharactersNoCopy",
+    RR_ScalarRval, nullptr, MM_Compose<MM_Buffer<1, 2, UniChar>, MM_CreateCFTypeRval> },
+  { "CFStringCreateWithCString", RR_ScalarRval },
+  { "CFStringCreateWithFormat", RR_ScalarRval },
+  { "CFStringGetBytes",
+    // Argument indexes are off by one here as the CFRange argument uses two slots.
+    RR_Compose<RR_ScalarRval,
+               RR_WriteOptionalBuffer<6, 7>,
+               RR_WriteOptionalBufferFixedSize<8, sizeof(CFIndex)>> },
+  { "CFStringGetCharacters",
+    // Argument indexes are off by one here as the CFRange argument uses two slots.
+    // We also need to specify the argument register with the range's length here.
+    RR_WriteBuffer<3, 2, UniChar>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_WriteBuffer<3, 2, UniChar>> },
+  { "CFStringGetCString", RR_Compose<RR_ScalarRval, RR_WriteBuffer<1, 2>> },
+  { "CFStringGetCStringPtr", nullptr, Preamble_VetoIfNotPassedThrough<0> },
+  { "CFStringGetIntValue", RR_ScalarRval },
+  { "CFStringGetLength", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CFStringGetMaximumSizeForEncoding", RR_ScalarRval },
+  { "CFStringHasPrefix", RR_ScalarRval },
+  { "CFStringTokenizerAdvanceToNextToken", RR_ScalarRval },
+  { "CFStringTokenizerCreate", RR_ScalarRval },
+  { "CFStringTokenizerGetCurrentTokenRange", RR_ComplexScalarRval },
+  { "CFURLCreateFromFileSystemRepresentation", RR_ScalarRval },
+  { "CFURLCreateFromFSRef", RR_ScalarRval },
+  { "CFURLCreateWithFileSystemPath", RR_ScalarRval },
+  { "CFURLCreateWithString", RR_ScalarRval },
+  { "CFURLGetFileSystemRepresentation", RR_Compose<RR_ScalarRval, RR_WriteBuffer<2, 3>> },
+  { "CFURLGetFSRef", RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<1, sizeof(FSRef)>> },
+  { "CFUUIDCreate", RR_ScalarRval, nullptr, MM_CreateCFTypeRval },
+  { "CFUUIDCreateString", RR_ScalarRval },
+  { "CFUUIDGetUUIDBytes", RR_ComplexScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CGAffineTransformConcat", RR_OversizeRval<sizeof(CGAffineTransform)> },
+  { "CGBitmapContextCreateImage",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CGBitmapContextCreateWithData",
+    RR_Compose<RR_ScalarRval, RR_CGBitmapContextCreateWithData>, nullptr,
+    MM_CGBitmapContextCreateWithData },
+  { "CGBitmapContextGetBytesPerRow", RR_ScalarRval },
+  { "CGBitmapContextGetHeight", RR_ScalarRval },
+  { "CGBitmapContextGetWidth", RR_ScalarRval },
+  { "CGColorRelease", RR_ScalarRval },
+  { "CGColorSpaceCopyICCProfile", RR_ScalarRval },
+  { "CGColorSpaceCreateDeviceGray", RR_ScalarRval, nullptr, MM_CreateCFTypeRval },
+  { "CGColorSpaceCreateDeviceRGB", RR_ScalarRval, nullptr, MM_CreateCFTypeRval },
+  { "CGColorSpaceCreatePattern", RR_ScalarRval },
+  { "CGColorSpaceRelease", RR_ScalarRval, nullptr, nullptr, Preamble_Veto<0> },
+  { "CGContextAddPath", nullptr, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>> },
+  { "CGContextBeginTransparencyLayerWithRect",
+    nullptr, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_StackArgumentData<sizeof(CGRect)>, MM_CFTypeArg<1>> },
+  { "CGContextClipToRect",
+    nullptr, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_StackArgumentData<sizeof(CGRect)>> },
+  { "CGContextClipToRects",
+    nullptr, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_Buffer<1, 2, CGRect>> },
+  { "CGContextConcatCTM",
+    nullptr, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_StackArgumentData<sizeof(CGAffineTransform)>> },
+  { "CGContextDrawImage",
+    RR_FlushCGContext<0>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_StackArgumentData<sizeof(CGRect)>,
+               MM_CFTypeArg<1>,
+               MM_FlushCGContext<0>> },
+  { "CGContextDrawLinearGradient",
+    RR_FlushCGContext<0>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_CFTypeArg<1>,
+               MM_StackArgumentData<2 * sizeof(CGPoint)>,
+               MM_FlushCGContext<0>> },
+  { "CGContextEndTransparencyLayer", nullptr, nullptr, MM_CFTypeArg<0> },
+  { "CGContextFillPath",
+    RR_FlushCGContext<0>, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_FlushCGContext<0>> },
+  { "CGContextFillRect",
+    RR_FlushCGContext<0>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_StackArgumentData<sizeof(CGRect)>, MM_FlushCGContext<0>> },
+  { "CGContextGetClipBoundingBox", RR_OversizeRval<sizeof(CGRect)> },
+  { "CGContextGetCTM", RR_OversizeRval<sizeof(CGAffineTransform)> },
+  { "CGContextGetType", RR_ScalarRval },
+  { "CGContextGetUserSpaceToDeviceSpaceTransform",
+    RR_OversizeRval<sizeof(CGAffineTransform)>, nullptr,
+    MM_Compose<MM_CFTypeArg<1>, MM_OversizeRval<sizeof(CGAffineTransform)>> },
+  { "CGContextRestoreGState",
+    nullptr, Preamble_CGContextRestoreGState, MM_UpdateCFTypeArg<0> },
+  { "CGContextRotateCTM", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSaveGState", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetAllowsFontSubpixelPositioning", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetAllowsFontSubpixelQuantization", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetAlpha", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetBaseCTM",
+    nullptr, nullptr,
+    MM_Compose<MM_UpdateCFTypeArg<0>, MM_StackArgumentData<sizeof(CGAffineTransform)>> },
+  { "CGContextSetCTM",
+    nullptr, nullptr,
+    MM_Compose<MM_UpdateCFTypeArg<0>, MM_StackArgumentData<sizeof(CGAffineTransform)>> },
+  { "CGContextSetGrayFillColor", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetRGBFillColor",
+    nullptr, nullptr,
+    MM_Compose<MM_UpdateCFTypeArg<0>, MM_StackArgumentData<sizeof(CGFloat)>> },
+  { "CGContextSetRGBStrokeColor",
+    nullptr, nullptr,
+    MM_Compose<MM_UpdateCFTypeArg<0>, MM_StackArgumentData<sizeof(CGFloat)>> },
+  { "CGContextSetShouldAntialias", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetShouldSmoothFonts", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetShouldSubpixelPositionFonts", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetShouldSubpixelQuantizeFonts", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetTextDrawingMode", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextSetTextMatrix",
+    nullptr, nullptr,
+    MM_Compose<MM_UpdateCFTypeArg<0>, MM_StackArgumentData<sizeof(CGAffineTransform)>> },
+  { "CGContextScaleCTM", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGContextStrokeLineSegments",
+    RR_FlushCGContext<0>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_Buffer<1, 2, CGPoint>, MM_FlushCGContext<0>> },
+  { "CGContextTranslateCTM", nullptr, nullptr, MM_UpdateCFTypeArg<0> },
+  { "CGDataProviderCreateWithData",
+    RR_Compose<RR_ScalarRval, RR_CGDataProviderCreateWithData>,
+    nullptr, MM_CGDataProviderCreateWithData },
+  { "CGDataProviderRelease", nullptr, nullptr, nullptr, Preamble_Veto<0> },
+  { "CGDisplayCopyColorSpace", RR_ScalarRval },
+  { "CGDisplayIOServicePort", RR_ScalarRval },
+  { "CGEventSourceCounterForEventType", RR_ScalarRval },
+  { "CGFontCopyTableForTag",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CGFontCopyTableTags",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CGFontCopyVariations",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CGFontCreateCopyWithVariations",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>, MM_CreateCFTypeRval> },
+  { "CGFontCreateWithDataProvider",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CGFontCreateWithFontName",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CGFontCreateWithPlatformFont", RR_ScalarRval },
+  { "CGFontGetAscent", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CGFontGetCapHeight", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CGFontGetDescent", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CGFontGetFontBBox",
+    RR_OversizeRval<sizeof(CGRect)>, nullptr,
+    MM_Compose<MM_CFTypeArg<1>, MM_OversizeRval<sizeof(CGRect)>> },
+  { "CGFontGetGlyphAdvances",
+    RR_Compose<RR_ScalarRval, RR_WriteBuffer<3, 2, int>>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_Buffer<1, 2, CGGlyph>, MM_WriteBuffer<3, 2, int>> },
+  { "CGFontGetGlyphBBoxes",
+    RR_Compose<RR_ScalarRval, RR_WriteBuffer<3, 2, CGRect>>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_Buffer<1, 2, CGGlyph>, MM_WriteBuffer<3, 2, CGRect>> },
+  { "CGFontGetGlyphPath", RR_ScalarRval },
+  { "CGFontGetLeading", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CGFontGetUnitsPerEm", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CGFontGetXHeight", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CGGradientCreateWithColorComponents",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_Buffer<1, 3, CGFloat>,
+               MM_Buffer<2, 3, CGFloat>,
+               MM_CreateCFTypeRval> },
+  { "CGImageGetHeight", RR_ScalarRval },
+  { "CGImageGetWidth", RR_ScalarRval },
+  { "CGImageRelease", RR_ScalarRval, nullptr, nullptr, Preamble_Veto<0> },
+  { "CGMainDisplayID", RR_ScalarRval },
+  { "CGPathAddPath" },
+  { "CGPathApply", nullptr, Preamble_CGPathApply },
+  { "CGPathContainsPoint", RR_ScalarRval },
+  { "CGPathCreateMutable", RR_ScalarRval },
+  { "CGPathCreateWithRoundedRect",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_StackArgumentData<sizeof(CGRect)>,
+               MM_BufferFixedSize<0, sizeof(CGAffineTransform)>,
+               MM_CreateCFTypeRval> },
+  { "CGPathGetBoundingBox", RR_OversizeRval<sizeof(CGRect)> },
+  { "CGPathGetCurrentPoint", RR_ComplexFloatRval },
+  { "CGPathIsEmpty", RR_ScalarRval },
+  { "CGSSetDebugOptions", RR_ScalarRval },
+  { "CGSShutdownServerConnections" },
+  { "CTFontCopyFamilyName",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CTFontCopyFeatures",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CTFontCopyFontDescriptor",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CTFontCopyGraphicsFont",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CTFontCopyTable",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CTFontCopyVariationAxes",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CTFontCreateForString",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>, MM_CreateCFTypeRval> },
+  { "CTFontCreatePathForGlyph",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_BufferFixedSize<2, sizeof(CGAffineTransform)>,
+               MM_CreateCFTypeRval> },
+  { "CTFontCreateWithFontDescriptor",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_BufferFixedSize<1, sizeof(CGAffineTransform)>,
+               MM_CreateCFTypeRval> },
+  { "CTFontCreateWithGraphicsFont",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_BufferFixedSize<1, sizeof(CGAffineTransform)>,
+               MM_CFTypeArg<2>,
+               MM_CreateCFTypeRval> },
+  { "CTFontCreateWithName",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_BufferFixedSize<1, sizeof(CGAffineTransform)>,
+               MM_CreateCFTypeRval> },
+  { "CTFontDescriptorCopyAttribute",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>, MM_CreateCFTypeRval> },
+  { "CTFontDescriptorCreateCopyWithAttributes",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>, MM_CreateCFTypeRval> },
+  { "CTFontDescriptorCreateMatchingFontDescriptors",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeArg<1>, MM_CreateCFTypeRval> },
+  { "CTFontDescriptorCreateWithAttributes",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CTFontDrawGlyphs",
+    RR_FlushCGContext<4>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_CFTypeArg<4>,
+               MM_Buffer<1, 3, CGGlyph>,
+               MM_Buffer<2, 3, CGPoint>,
+               MM_FlushCGContext<4>> },
+  { "CTFontGetAdvancesForGlyphs",
+    RR_Compose<RR_FloatRval, RR_WriteOptionalBuffer<3, 4, CGSize>>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_Buffer<2, 4, CGGlyph>, MM_WriteBuffer<3, 4, CGSize>> },
+  { "CTFontGetAscent", RR_FloatRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetBoundingBox",
+    RR_OversizeRval<sizeof(CGRect)>, nullptr,
+    MM_Compose<MM_CFTypeArg<1>, MM_OversizeRval<sizeof(CGRect)>> },
+  { "CTFontGetBoundingRectsForGlyphs",
+    // Argument indexes here are off by one due to the oversize rval.
+    RR_Compose<RR_OversizeRval<sizeof(CGRect)>, RR_WriteOptionalBuffer<4, 5, CGRect>>, nullptr,
+    MM_Compose<MM_CFTypeArg<1>,
+               MM_Buffer<3, 5, CGGlyph>,
+               MM_OversizeRval<sizeof(CGRect)>,
+               MM_WriteBuffer<4, 5, CGRect>> },
+  { "CTFontGetCapHeight", RR_FloatRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetDescent", RR_FloatRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetGlyphCount", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetGlyphsForCharacters",
+    RR_Compose<RR_ScalarRval, RR_WriteBuffer<2, 3, CGGlyph>>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>, MM_Buffer<1, 3, UniChar>, MM_WriteBuffer<2, 3, CGGlyph>> },
+  { "CTFontGetLeading", RR_FloatRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetSize", RR_FloatRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetSymbolicTraits", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetUnderlinePosition", RR_FloatRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetUnderlineThickness", RR_FloatRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetUnitsPerEm", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontGetXHeight", RR_FloatRval, nullptr, MM_CFTypeArg<0> },
+  { "CTFontManagerCopyAvailableFontFamilyNames", RR_ScalarRval },
+  { "CTFontManagerRegisterFontsForURLs", RR_ScalarRval },
+  { "CTFontManagerSetAutoActivationSetting" },
+  { "CTLineCreateWithAttributedString",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CreateCFTypeRval> },
+  { "CTLineGetGlyphRuns",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeRval> },
+  { "CTRunGetAttributes",
+    RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeRval> },
+  { "CTRunGetGlyphCount", RR_ScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CTRunGetGlyphsPtr",
+    RR_CTRunGetElements<CGGlyph, CTRunGetGlyphs>, nullptr,
+    MM_CTRunGetElements<CGGlyph, CTRunGetGlyphs> },
+  { "CTRunGetPositionsPtr",
+    RR_CTRunGetElements<CGPoint, CTRunGetPositions>, nullptr,
+    MM_CTRunGetElements<CGPoint, CTRunGetPositions> },
+  { "CTRunGetStringIndicesPtr",
+    RR_CTRunGetElements<CFIndex, CTRunGetStringIndices>, nullptr,
+    MM_CTRunGetElements<CFIndex, CTRunGetStringIndices> },
+  { "CTRunGetStringRange", RR_ComplexScalarRval, nullptr, MM_CFTypeArg<0> },
+  { "CTRunGetTypographicBounds",
+    // Argument indexes are off by one here as the CFRange argument uses two slots.
+    RR_Compose<RR_FloatRval,
+               RR_WriteOptionalBufferFixedSize<3, sizeof(CGFloat)>,
+               RR_WriteOptionalBufferFixedSize<4, sizeof(CGFloat)>,
+               RR_WriteOptionalBufferFixedSize<5, sizeof(CGFloat)>>, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_WriteBufferFixedSize<3, sizeof(CGFloat)>,
+               MM_WriteBufferFixedSize<4, sizeof(CGFloat)>,
+               MM_WriteBufferFixedSize<5, sizeof(CGFloat)>> },
+  { "CUIDraw",
+    nullptr, nullptr,
+    MM_Compose<MM_CFTypeArg<0>,
+               MM_CFTypeArg<1>,
+               MM_CFTypeArg<2>,
+               MM_StackArgumentData<sizeof(CGRect)>> },
+  { "FSCompareFSRefs", RR_ScalarRval },
+  { "FSGetVolumeInfo",
+    RR_Compose<RR_ScalarRval,
+               RR_WriteBufferFixedSize<5, sizeof(HFSUniStr255)>,
+               RR_WriteBufferFixedSize<6, sizeof(FSRef)>> },
+  { "FSFindFolder", RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<3, sizeof(FSRef)>> },
+  { "Gestalt", RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<1, sizeof(SInt32)>> },
+  { "GetEventClass", RR_ScalarRval },
+  { "GetCurrentEventQueue", RR_ScalarRval },
+  { "GetCurrentProcess",
+    RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(ProcessSerialNumber)>> },
+  { "GetEventAttributes", RR_ScalarRval },
+  { "GetEventDispatcherTarget", RR_ScalarRval },
+  { "GetEventKind", RR_ScalarRval },
+  { "HIThemeDrawButton",
+    RR_Compose<RR_WriteBufferFixedSize<4, sizeof(HIRect)>, RR_ScalarRval>, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIRect)>,
+               MM_BufferFixedSize<1, sizeof(HIThemeButtonDrawInfo)>,
+               MM_UpdateCFTypeArg<2>,
+               MM_WriteBufferFixedSize<4, sizeof(HIRect)>> },
+  { "HIThemeDrawFrame",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIRect)>,
+               MM_BufferFixedSize<1, sizeof(HIThemeFrameDrawInfo)>,
+               MM_UpdateCFTypeArg<2>> },
+  { "HIThemeDrawGroupBox",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIRect)>,
+               MM_BufferFixedSize<1, sizeof(HIThemeGroupBoxDrawInfo)>,
+               MM_UpdateCFTypeArg<2>> },
+  { "HIThemeDrawGrowBox",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIPoint)>,
+               MM_BufferFixedSize<1, sizeof(HIThemeGrowBoxDrawInfo)>,
+               MM_UpdateCFTypeArg<2>> },
+  { "HIThemeDrawMenuBackground",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIRect)>,
+               MM_BufferFixedSize<1, sizeof(HIThemeMenuDrawInfo)>,
+               MM_UpdateCFTypeArg<2>> },
+  { "HIThemeDrawMenuItem",
+    RR_Compose<RR_WriteBufferFixedSize<5, sizeof(HIRect)>, RR_ScalarRval>, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIRect)>,
+               MM_BufferFixedSize<1, sizeof(HIRect)>,
+               MM_BufferFixedSize<2, sizeof(HIThemeMenuItemDrawInfo)>,
+               MM_UpdateCFTypeArg<3>,
+               MM_WriteBufferFixedSize<5, sizeof(HIRect)>> },
+  { "HIThemeDrawMenuSeparator",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIRect)>,
+               MM_BufferFixedSize<1, sizeof(HIRect)>,
+               MM_BufferFixedSize<2, sizeof(HIThemeMenuItemDrawInfo)>,
+               MM_UpdateCFTypeArg<3>> },
+  { "HIThemeDrawSeparator",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIRect)>,
+               MM_BufferFixedSize<1, sizeof(HIThemeSeparatorDrawInfo)>,
+               MM_UpdateCFTypeArg<2>> },
+  { "HIThemeDrawTabPane",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIRect)>,
+               MM_BufferFixedSize<1, sizeof(HIThemeTabPaneDrawInfo)>,
+               MM_UpdateCFTypeArg<2>> },
+  { "HIThemeDrawTrack",
+    RR_ScalarRval, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIThemeTrackDrawInfo)>,
+               MM_BufferFixedSize<1, sizeof(HIRect)>,
+               MM_UpdateCFTypeArg<2>> },
+  { "HIThemeGetGrowBoxBounds",
+    RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<2, sizeof(HIRect)>>, nullptr,
+    MM_Compose<MM_BufferFixedSize<0, sizeof(HIPoint)>,
+               MM_BufferFixedSize<1, sizeof(HIThemeGrowBoxDrawInfo)>,
+               MM_WriteBufferFixedSize<2, sizeof(HIRect)>> },
+  { "HIThemeSetFill", RR_ScalarRval, nullptr, MM_UpdateCFTypeArg<2> },
+  { "IORegistryEntrySearchCFProperty", RR_ScalarRval },
+  { "LSCopyAllHandlersForURLScheme", RR_ScalarRval },
+  { "LSCopyApplicationForMIMEType",
+    RR_Compose<RR_ScalarRval, RR_WriteOptionalBufferFixedSize<2, sizeof(CFURLRef)>> },
+  { "LSCopyItemAttribute",
+    RR_Compose<RR_ScalarRval, RR_WriteOptionalBufferFixedSize<3, sizeof(CFTypeRef)>> },
+  { "LSCopyKindStringForMIMEType",
+    RR_Compose<RR_ScalarRval, RR_WriteOptionalBufferFixedSize<1, sizeof(CFStringRef)>> },
+  { "LSGetApplicationForInfo",
+    RR_Compose<RR_ScalarRval,
+               RR_WriteOptionalBufferFixedSize<4, sizeof(FSRef)>,
+               RR_WriteOptionalBufferFixedSize<5, sizeof(CFURLRef)>> },
+  { "LSGetApplicationForURL",
+    RR_Compose<RR_ScalarRval,
+               RR_WriteOptionalBufferFixedSize<2, sizeof(FSRef)>,
+               RR_WriteOptionalBufferFixedSize<3, sizeof(CFURLRef)>> },
+  { "NSClassFromString", RR_ScalarRval, nullptr, MM_Compose<MM_CFTypeArg<0>, MM_CFTypeRval> },
+  { "NSRectFill", nullptr, nullptr, MM_NoOp },
+  { "NSSearchPathForDirectoriesInDomains", RR_ScalarRval },
+  { "NSSetFocusRingStyle", nullptr, nullptr, MM_NoOp },
+  { "NSTemporaryDirectory", RR_ScalarRval },
+  { "OSSpinLockLock", nullptr, Preamble_OSSpinLockLock },
+  { "ReleaseEvent", RR_ScalarRval },
+  { "RemoveEventFromQueue", RR_ScalarRval },
+  { "RetainEvent", RR_ScalarRval },
+  { "SCDynamicStoreCopyProxies", RR_ScalarRval },
+  { "SCDynamicStoreCreate", RR_ScalarRval },
+  { "SCDynamicStoreCreateRunLoopSource", RR_ScalarRval },
+  { "SCDynamicStoreKeyCreateProxies", RR_ScalarRval },
+  { "SCDynamicStoreSetNotificationKeys", RR_ScalarRval },
+  { "SendEventToEventTarget", RR_ScalarRval },
+
+  // These are not public APIs, but other redirected functions may be aliases
+  // for these which are dynamically installed on the first call in a way that
+  // our redirection mechanism doesn't completely account for.
+  { "SLDisplayCopyColorSpace", RR_ScalarRval },
+  { "SLDisplayIOServicePort", RR_ScalarRval },
+  { "SLEventSourceCounterForEventType", RR_ScalarRval },
+  { "SLMainDisplayID", RR_ScalarRval },
+  { "SLSSetDenyWindowServerConnections", RR_ScalarRval },
+  { "SLSShutdownServerConnections" },
+};
+
+///////////////////////////////////////////////////////////////////////////////
 // Redirection generation
 ///////////////////////////////////////////////////////////////////////////////
 
-#define MAKE_REDIRECTION_ENTRY(aName, ...)          \
-  { #aName, nullptr, nullptr, __VA_ARGS__ },
+size_t
+NumRedirections()
+{
+  return ArrayLength(gSystemRedirections);
+}
+
+static Redirection* gRedirections;
+
+Redirection&
+GetRedirection(size_t aCallId)
+{
+  MOZ_RELEASE_ASSERT(aCallId < ArrayLength(gSystemRedirections));
+  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()
+{
+  size_t numRedirections = NumRedirections();
+  gRedirections = new Redirection[numRedirections];
+  PodZero(gRedirections, numRedirections);
 
-Redirection gRedirections[] = {
-  FOR_EACH_REDIRECTION(MAKE_REDIRECTION_ENTRY)
-  { }
-};
+  for (size_t i = 0; i < numRedirections; i++) {
+    const SystemRedirection& systemRedirection = gSystemRedirections[i];
+    Redirection& redirection = gRedirections[i];
+
+    redirection.mName = systemRedirection.mName;
+    redirection.mSaveOutput = systemRedirection.mSaveOutput;
+    redirection.mPreamble = systemRedirection.mPreamble;
+    redirection.mMiddlemanCall = systemRedirection.mMiddlemanCall;
+    redirection.mMiddlemanPreamble = systemRedirection.mMiddlemanPreamble;
+
+    redirection.mBaseFunction = FunctionStartAddress(redirection);
+    redirection.mOriginalFunction = redirection.mBaseFunction;
 
-#undef MAKE_REDIRECTION_ENTRY
+    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) {
+          redirection.mBaseFunction = nullptr;
+          break;
+        }
+      }
+    }
+  }
+
+  // Bind the gOriginal functions to their redirections' base addresses until we
+  // finish installing redirections.
+  LateInitializeRedirections();
+}
+
+void
+LateInitializeRedirections()
+{
+#define INIT_ORIGINAL_FUNCTION(aName)        \
+  gOriginal_ ##aName = OriginalFunction(#aName);
+
+  FOR_EACH_ORIGINAL_FUNCTION(INIT_ORIGINAL_FUNCTION)
+
+#undef INIT_ORIGINAL_FUNCTION
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Direct system call API
 ///////////////////////////////////////////////////////////////////////////////
 
 const char*
 SymbolNameRaw(void* aPtr)
 {
   Dl_info info;
   return (dladdr(aPtr, &info) && info.dli_sname) ? info.dli_sname : "???";
 }
 
 void*
 DirectAllocateMemory(void* aAddress, size_t aSize)
 {
-  void* res = OriginalCall(mmap, void*,
-                           aAddress, aSize, PROT_READ | PROT_WRITE | PROT_EXEC,
-                           MAP_ANON | MAP_PRIVATE, -1, 0);
+  void* res = CallFunction<void*>(gOriginal_mmap, aAddress, aSize,
+                                  PROT_READ | PROT_WRITE | PROT_EXEC,
+                                  MAP_ANON | MAP_PRIVATE, -1, 0);
   MOZ_RELEASE_ASSERT(res && res != (void*)-1);
   return res;
 }
 
 void
 DirectDeallocateMemory(void* aAddress, size_t aSize)
 {
-  ssize_t rv = OriginalCall(munmap, int, aAddress, aSize);
+  ssize_t rv = CallFunction<int>(gOriginal_munmap, aAddress, aSize);
   MOZ_RELEASE_ASSERT(rv >= 0);
 }
 
 void
 DirectWriteProtectMemory(void* aAddress, size_t aSize, bool aExecutable,
                          bool aIgnoreFailures /* = false */)
 {
-  ssize_t rv = OriginalCall(mprotect, int, aAddress, aSize,
-                            PROT_READ | (aExecutable ? PROT_EXEC : 0));
+  ssize_t rv = CallFunction<int>(gOriginal_mprotect, aAddress, aSize,
+                                 PROT_READ | (aExecutable ? PROT_EXEC : 0));
   MOZ_RELEASE_ASSERT(aIgnoreFailures || rv == 0);
 }
 
 void
 DirectUnprotectMemory(void* aAddress, size_t aSize, bool aExecutable,
                       bool aIgnoreFailures /* = false */)
 {
-  ssize_t rv = OriginalCall(mprotect, int, aAddress, aSize,
-                            PROT_READ | PROT_WRITE | (aExecutable ? PROT_EXEC : 0));
+  ssize_t rv = CallFunction<int>(gOriginal_mprotect, aAddress, aSize,
+                                 PROT_READ | PROT_WRITE | (aExecutable ? PROT_EXEC : 0));
   MOZ_RELEASE_ASSERT(aIgnoreFailures || rv == 0);
 }
 
 void
 DirectSeekFile(FileHandle aFd, uint64_t aOffset)
 {
   static_assert(sizeof(uint64_t) == sizeof(off_t), "off_t should have 64 bits");
-  ssize_t rv = HANDLE_EINTR(OriginalCall(lseek, int, aFd, aOffset, SEEK_SET));
+  ssize_t rv = HANDLE_EINTR(CallFunction<int>(gOriginal_lseek, aFd, aOffset, SEEK_SET));
   MOZ_RELEASE_ASSERT(rv >= 0);
 }
 
 FileHandle
 DirectOpenFile(const char* aFilename, bool aWriting)
 {
   int flags = aWriting ? (O_WRONLY | O_CREAT | O_TRUNC) : O_RDONLY;
   int perms = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
-  int fd = HANDLE_EINTR(OriginalCall(open, int, aFilename, flags, perms));
+  int fd = HANDLE_EINTR(CallFunction<int>(gOriginal_open, aFilename, flags, perms));
   MOZ_RELEASE_ASSERT(fd > 0);
   return fd;
 }
 
 void
 DirectCloseFile(FileHandle aFd)
 {
-  ssize_t rv = HANDLE_EINTR(OriginalCall(close, int, aFd));
+  ssize_t rv = HANDLE_EINTR(CallFunction<int>(gOriginal_close, aFd));
   MOZ_RELEASE_ASSERT(rv >= 0);
 }
 
 void
 DirectDeleteFile(const char* aFilename)
 {
   ssize_t rv = unlink(aFilename);
   MOZ_RELEASE_ASSERT(rv >= 0 || errno == ENOENT);
 }
 
 void
 DirectWrite(FileHandle aFd, const void* aData, size_t aSize)
 {
-  ssize_t rv = HANDLE_EINTR(OriginalCall(write, int, aFd, aData, aSize));
+  ssize_t rv = HANDLE_EINTR(CallFunction<int>(gOriginal_write, aFd, aData, aSize));
   MOZ_RELEASE_ASSERT((size_t) rv == aSize);
 }
 
 void
 DirectPrint(const char* aString)
 {
   DirectWrite(STDERR_FILENO, aString, strlen(aString));
 }
 
 size_t
 DirectRead(FileHandle aFd, void* aData, size_t aSize)
 {
   // Clear the memory in case it is write protected by the memory snapshot
   // mechanism.
   memset(aData, 0, aSize);
-  ssize_t rv = HANDLE_EINTR(OriginalCall(read, int, aFd, aData, aSize));
+  ssize_t rv = HANDLE_EINTR(CallFunction<int>(gOriginal_read, aFd, aData, aSize));
   MOZ_RELEASE_ASSERT(rv >= 0);
   return (size_t) rv;
 }
 
 void
 DirectCreatePipe(FileHandle* aWriteFd, FileHandle* aReadFd)
 {
   int fds[2];
-  ssize_t rv = OriginalCall(pipe, int, fds);
+  ssize_t rv = CallFunction<int>(gOriginal_pipe, fds);
   MOZ_RELEASE_ASSERT(rv >= 0);
   *aWriteFd = fds[1];
   *aReadFd = fds[0];
 }
 
 static double gAbsoluteToNanosecondsRate;
 
 void
@@ -2435,17 +2781,17 @@ InitializeCurrentTime()
   Nanoseconds rate = AbsoluteToNanoseconds(time);
   MOZ_RELEASE_ASSERT(!rate.hi);
   gAbsoluteToNanosecondsRate = rate.lo / 1000000.0;
 }
 
 double
 CurrentTime()
 {
-  return OriginalCall(mach_absolute_time, int64_t) * gAbsoluteToNanosecondsRate / 1000.0;
+  return CallFunction<int64_t>(gOriginal_mach_absolute_time) * gAbsoluteToNanosecondsRate / 1000.0;
 }
 
 void
 DirectSpawnThread(void (*aFunction)(void*), void* aArgument)
 {
   MOZ_RELEASE_ASSERT(IsMiddleman() || AreThreadEventsPassedThrough());
 
   pthread_attr_t attr;
@@ -2454,17 +2800,18 @@ DirectSpawnThread(void (*aFunction)(void
 
   rv = pthread_attr_setstacksize(&attr, 2 * 1024 * 1024);
   MOZ_RELEASE_ASSERT(rv == 0);
 
   rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
   MOZ_RELEASE_ASSERT(rv == 0);
 
   pthread_t pthread;
-  rv = OriginalCall(pthread_create, int, &pthread, &attr, (void* (*)(void*)) aFunction, aArgument);
+  rv = CallFunction<int>(gOriginal_pthread_create,
+                         &pthread, &attr, (void* (*)(void*)) aFunction, aArgument);
   MOZ_RELEASE_ASSERT(rv == 0);
 
   rv = pthread_attr_destroy(&attr);
   MOZ_RELEASE_ASSERT(rv == 0);
 }
 
 } // recordreplay
 } // mozilla
--- a/xpcom/base/nsISupportsImpl.h
+++ b/xpcom/base/nsISupportsImpl.h
@@ -606,17 +606,17 @@ public:
  * given non-XPCOM <i>_class</i>.
  *
  * @param _class The name of the class implementing the method
  * @param optional override Mark the AddRef & Release methods as overrides.
  */
 #define NS_INLINE_DECL_REFCOUNTING(_class, ...)                               \
   NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, delete(this), __VA_ARGS__)
 
-#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, _decl, ...)        \
+#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, _decl, _recording, ...) \
 public:                                                                       \
   _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ {                   \
     MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                                \
     MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                      \
     nsrefcnt count = ++mRefCnt;                                               \
     NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                       \
     return (nsrefcnt) count;                                                  \
   }                                                                           \
@@ -627,36 +627,58 @@ public:                                 
     if (count == 0) {                                                         \
       delete (this);                                                          \
       return 0;                                                               \
     }                                                                         \
     return count;                                                             \
   }                                                                           \
   typedef mozilla::TrueType HasThreadSafeRefCnt;                              \
 protected:                                                                    \
-  ::mozilla::ThreadSafeAutoRefCnt mRefCnt;                                    \
+  ::mozilla::ThreadSafeAutoRefCntWithRecording<_recording> mRefCnt;           \
 public:
 
 /**
  * Use this macro to declare and implement the AddRef & Release methods for a
  * given non-XPCOM <i>_class</i> in a threadsafe manner.
  *
  * DOES NOT DO REFCOUNT STABILIZATION!
  *
  * @param _class The name of the class implementing the method
  */
 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class, ...)                    \
-NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_, __VA_ARGS__)
+NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_,                \
+                                           mozilla::recordreplay::Behavior::DontPreserve, \
+                                           __VA_ARGS__)
 
 /**
  * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING with AddRef & Release declared
  * virtual.
  */
 #define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(_class, ...)            \
-NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_IMETHOD_, __VA_ARGS__)
+NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_IMETHOD_,               \
+                                           mozilla::recordreplay::Behavior::DontPreserve, \
+                                           __VA_ARGS__)
+
+/**
+ * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING except that reference changes
+ * are recorded and replayed.
+ */
+#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_RECORDED(_class, ...)           \
+NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_,                \
+                                           mozilla::recordreplay::Behavior::Preserve, \
+                                           __VA_ARGS__)
+
+/**
+ * Like NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING except that reference
+ * changes are recorded and replayed.
+ */
+#define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_RECORDED(_class, ...)   \
+NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_IMETHOD_,               \
+                                           mozilla::recordreplay::Behavior::Preserve, \
+                                           __VA_ARGS__)
 
 /**
  * Use this macro in interface classes that you want to be able to reference
  * using RefPtr, but don't want to provide a refcounting implemenation. The
  * refcounting implementation can be provided by concrete subclasses that
  * implement the interface.
  */
 #define NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING                               \