1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "RecordReplay.h"
9 #include "js/GCAnnotations.h"
10 #include "mozilla/Atomics.h"
11 #include "mozilla/Casting.h"
12 #include "mozilla/Utf8.h"
16 // Recording and replaying is only enabled on Mac nightlies.
17 #if defined(XP_MACOSX) && defined(NIGHTLY_BUILD)
18 # define ENABLE_RECORD_REPLAY
21 #ifdef ENABLE_RECORD_REPLAY
25 namespace mozilla::recordreplay
{
28 #define FOR_EACH_INTERFACE(Macro) \
29 Macro(InternalAreThreadEventsPassedThrough, bool, (), ()) \
30 Macro(InternalAreThreadEventsDisallowed, bool, (), ()) \
31 Macro(InternalRecordReplayValue, size_t, (size_t aValue), (aValue)) \
32 Macro(InternalHasDivergedFromRecording, bool, (), ()) \
33 Macro(InternalGeneratePLDHashTableCallbacks, const PLDHashTableOps*, \
34 (const PLDHashTableOps* aOps), (aOps)) \
35 Macro(InternalUnwrapPLDHashTableCallbacks, const PLDHashTableOps*, \
36 (const PLDHashTableOps* aOps), (aOps)) \
37 Macro(InternalThingIndex, size_t, (void* aThing), (aThing)) \
38 Macro(InternalVirtualThingName, const char*, (void* aThing), (aThing)) \
39 Macro(ExecutionProgressCounter, ProgressCounter*, (), ()) \
40 Macro(NewTimeWarpTarget, ProgressCounter, (), ()) \
41 Macro(ShouldUpdateProgressCounter, bool, (const char* aURL), (aURL)) \
42 Macro(DefineRecordReplayControlObject, bool, (void* aCx, void* aObj), \
45 #define FOR_EACH_INTERFACE_VOID(Macro) \
46 Macro(InternalBeginOrderedAtomicAccess, (const void* aValue), (aValue)) \
47 Macro(InternalEndOrderedAtomicAccess, (), ()) \
48 Macro(InternalBeginPassThroughThreadEvents, (), ()) \
49 Macro(InternalEndPassThroughThreadEvents, (), ()) \
50 Macro(InternalBeginPassThroughThreadEventsWithLocalReplay, (), ()) \
51 Macro(InternalEndPassThroughThreadEventsWithLocalReplay, (), ()) \
52 Macro(InternalBeginDisallowThreadEvents, (), ()) \
53 Macro(InternalEndDisallowThreadEvents, (), ()) \
54 Macro(InternalRecordReplayBytes, (void* aData, size_t aSize), \
56 Macro(InternalInvalidateRecording, (const char* aWhy), (aWhy)) \
57 Macro(InternalDestroyPLDHashTableCallbacks, (const PLDHashTableOps* aOps), \
59 Macro(InternalMovePLDHashTableContents, \
60 (const PLDHashTableOps* aFirstOps, const PLDHashTableOps* aSecondOps), \
61 (aFirstOps, aSecondOps)) \
62 Macro(InternalHoldJSObject, (void* aJSObj), (aJSObj)) \
63 Macro(InternalRecordReplayAssert, (const char* aFormat, va_list aArgs), \
65 Macro(InternalRecordReplayAssertBytes, (const void* aData, size_t aSize), \
67 Macro(InternalRegisterThing, (void* aThing), (aThing)) \
68 Macro(InternalUnregisterThing, (void* aThing), (aThing)) \
69 Macro(BeginContentParse, \
70 (const void* aToken, const char* aURL, const char* aContentType), \
71 (aToken, aURL, aContentType)) \
72 Macro(AddContentParseData8, \
73 (const void* aToken, const mozilla::Utf8Unit* aUtf8Buffer, \
75 (aToken, aUtf8Buffer, aLength)) \
76 Macro(AddContentParseData16, \
77 (const void* aToken, const char16_t* aBuffer, size_t aLength), \
78 (aToken, aBuffer, aLength)) \
79 Macro(EndContentParse, (const void* aToken), (aToken))
82 #define DECLARE_SYMBOL(aName, aReturnType, aFormals, _) \
83 static aReturnType(*gPtr##aName) aFormals;
84 #define DECLARE_SYMBOL_VOID(aName, aFormals, _) \
85 DECLARE_SYMBOL(aName, void, aFormals, _)
87 FOR_EACH_INTERFACE(DECLARE_SYMBOL
)
88 FOR_EACH_INTERFACE_VOID(DECLARE_SYMBOL_VOID
)
91 #undef DECLARE_SYMBOL_VOID
93 static void* LoadSymbol(const char* aName
) {
94 #ifdef ENABLE_RECORD_REPLAY
95 void* rv
= dlsym(RTLD_DEFAULT
, aName
);
97 fprintf(stderr
, "Record/Replay LoadSymbol failed: %s\n", aName
);
98 MOZ_CRASH("LoadSymbol");
106 void Initialize(int aArgc
, char* aArgv
[]) {
107 // Only initialize if the right command line option was specified.
109 for (int i
= 0; i
< aArgc
; i
++) {
110 if (!strcmp(aArgv
[i
], gProcessKindOption
)) {
119 void (*initialize
)(int, char**);
120 BitwiseCast(LoadSymbol("RecordReplayInterface_Initialize"), &initialize
);
125 #define INIT_SYMBOL(aName, _1, _2, _3) \
126 BitwiseCast(LoadSymbol("RecordReplayInterface_" #aName), &gPtr##aName);
127 #define INIT_SYMBOL_VOID(aName, _2, _3) INIT_SYMBOL(aName, void, _2, _3)
129 FOR_EACH_INTERFACE(INIT_SYMBOL
)
130 FOR_EACH_INTERFACE_VOID(INIT_SYMBOL_VOID
)
133 #undef INIT_SYMBOL_VOID
135 initialize(aArgc
, aArgv
);
138 // Record/replay API functions can't GC, but we can't use
139 // JS::AutoSuppressGCAnalysis here due to linking issues.
140 struct AutoSuppressGCAnalysis
{
141 AutoSuppressGCAnalysis() {}
142 ~AutoSuppressGCAnalysis() {
144 // Need nontrivial destructor.
145 static Atomic
<int, SequentiallyConsistent
, Behavior::DontPreserve
> dummy
;
149 } JS_HAZ_GC_SUPPRESSED
;
151 #define DEFINE_WRAPPER(aName, aReturnType, aFormals, aActuals) \
152 aReturnType aName aFormals { \
153 AutoSuppressGCAnalysis suppress; \
154 MOZ_ASSERT(IsRecordingOrReplaying() || IsMiddleman()); \
155 return gPtr##aName aActuals; \
158 #define DEFINE_WRAPPER_VOID(aName, aFormals, aActuals) \
159 void aName aFormals { \
160 AutoSuppressGCAnalysis suppress; \
161 MOZ_ASSERT(IsRecordingOrReplaying() || IsMiddleman()); \
162 gPtr##aName aActuals; \
165 FOR_EACH_INTERFACE(DEFINE_WRAPPER
)
166 FOR_EACH_INTERFACE_VOID(DEFINE_WRAPPER_VOID
)
168 #undef DEFINE_WRAPPER
169 #undef DEFINE_WRAPPER_VOID
171 #ifdef ENABLE_RECORD_REPLAY
173 bool gIsRecordingOrReplaying
;
178 #endif // ENABLE_RECORD_REPLAY
180 #undef ENABLE_RECORD_REPLAY
182 } // namespace mozilla::recordreplay