/src/mozilla-central/mfbt/RecordReplay.h
Line | Count | Source (jump to first uncovered line) |
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/. */ |
6 | | |
7 | | /* Public API for Web Replay. */ |
8 | | |
9 | | #ifndef mozilla_RecordReplay_h |
10 | | #define mozilla_RecordReplay_h |
11 | | |
12 | | #include "mozilla/Attributes.h" |
13 | | #include "mozilla/GuardObjects.h" |
14 | | #include "mozilla/TemplateLib.h" |
15 | | #include "mozilla/Types.h" |
16 | | |
17 | | #include <functional> |
18 | | #include <stdarg.h> |
19 | | |
20 | | struct PLDHashTableOps; |
21 | | struct JSContext; |
22 | | class JSObject; |
23 | | |
24 | | namespace mozilla { |
25 | | namespace recordreplay { |
26 | | |
27 | | // Record/Replay Overview. |
28 | | // |
29 | | // Firefox content processes can be specified to record or replay their |
30 | | // behavior. Whether a process is recording or replaying is initialized at the |
31 | | // start of the main() routine, and is afterward invariant for the process. |
32 | | // |
33 | | // Recording and replaying works by controlling non-determinism in the browser: |
34 | | // non-deterministic behaviors are initially recorded, then later replayed |
35 | | // exactly to force the browser to behave deterministically. Two types of |
36 | | // non-deterministic behaviors are captured: intra-thread and inter-thread. |
37 | | // Intra-thread non-deterministic behaviors are non-deterministic even in the |
38 | | // absence of actions by other threads, and inter-thread non-deterministic |
39 | | // behaviors are those affected by interleaving execution with other threads. |
40 | | // |
41 | | // Intra-thread non-determinism is recorded and replayed as a stream of events |
42 | | // for each thread. Most events originate from calls to system library |
43 | | // functions (for i/o and such); the record/replay system handles these |
44 | | // internally by redirecting these library functions so that code can be |
45 | | // injected and the event recorded/replayed. Events can also be manually |
46 | | // performed using the RecordReplayValue and RecordReplayBytes APIs below. |
47 | | // |
48 | | // Inter-thread non-determinism is recorded and replayed by keeping track of |
49 | | // the order in which threads acquire locks or perform atomic accesses. If the |
50 | | // program is data race free, then reproducing the order of these operations |
51 | | // will give an interleaving that is functionally (if not exactly) the same |
52 | | // as during the recording. As for intra-thread non-determinism, system library |
53 | | // redirections are used to capture most inter-thread non-determinism, but the |
54 | | // {Begin,End}OrderedAtomicAccess APIs below can be used to add new ordering |
55 | | // constraints. |
56 | | // |
57 | | // Some behaviors can differ between recording and replay. Mainly, pointer |
58 | | // values can differ, and JS GCs can occur at different points (a more complete |
59 | | // list is at the URL below). Some of the APIs below are used to accommodate |
60 | | // these behaviors and keep the replaying process on track. |
61 | | // |
62 | | // A third process type, middleman processes, are normal content processes |
63 | | // which facilitate communication with recording and replaying processes, |
64 | | // managing the graphics data they generate, and running devtools code that |
65 | | // interacts with them. |
66 | | // |
67 | | // This file contains the main public API for places where mozilla code needs |
68 | | // to interact with the record/replay system. There are a few additional public |
69 | | // APIs in toolkit/recordreplay/ipc, for the IPC performed by |
70 | | // recording/replaying processes and middleman processes. |
71 | | // |
72 | | // A more complete description of Web Replay can be found at this URL: |
73 | | // https://developer.mozilla.org/en-US/docs/WebReplay |
74 | | |
75 | | /////////////////////////////////////////////////////////////////////////////// |
76 | | // Public API |
77 | | /////////////////////////////////////////////////////////////////////////////// |
78 | | |
79 | | // Recording and replaying is only enabled on Mac nightlies. |
80 | | #if defined(XP_MACOSX) && defined(NIGHTLY_BUILD) |
81 | | |
82 | | extern MFBT_DATA bool gIsRecordingOrReplaying; |
83 | | extern MFBT_DATA bool gIsRecording; |
84 | | extern MFBT_DATA bool gIsReplaying; |
85 | | extern MFBT_DATA bool gIsMiddleman; |
86 | | |
87 | | // Get the kind of recording/replaying process this is, if any. |
88 | | static inline bool IsRecordingOrReplaying() { return gIsRecordingOrReplaying; } |
89 | | static inline bool IsRecording() { return gIsRecording; } |
90 | | static inline bool IsReplaying() { return gIsReplaying; } |
91 | | static inline bool IsMiddleman() { return gIsMiddleman; } |
92 | | |
93 | | #else // XP_MACOSX && NIGHTLY_BUILD |
94 | | |
95 | | // On unsupported platforms, getting the kind of process is a no-op. |
96 | 0 | static inline bool IsRecordingOrReplaying() { return false; } |
97 | 0 | static inline bool IsRecording() { return false; } |
98 | 0 | static inline bool IsReplaying() { return false; } |
99 | 0 | static inline bool IsMiddleman() { return false; } |
100 | | |
101 | | #endif // XP_MACOSX && NIGHTLY_BUILD |
102 | | |
103 | | // Mark a region which occurs atomically wrt the recording. No two threads can |
104 | | // be in an atomic region at once, and the order in which atomic sections are |
105 | | // executed by the various threads will be the same in the replay as in the |
106 | | // recording. These calls have no effect when not recording/replaying. |
107 | | static inline void BeginOrderedAtomicAccess(); |
108 | | static inline void EndOrderedAtomicAccess(); |
109 | | |
110 | | // RAII class for an atomic access. |
111 | | struct MOZ_RAII AutoOrderedAtomicAccess |
112 | | { |
113 | | AutoOrderedAtomicAccess() { BeginOrderedAtomicAccess(); } |
114 | | ~AutoOrderedAtomicAccess() { EndOrderedAtomicAccess(); } |
115 | | }; |
116 | | |
117 | | // Mark a region where thread events are passed through the record/replay |
118 | | // system. While recording, no information from system calls or other events |
119 | | // will be recorded for the thread. While replaying, system calls and other |
120 | | // events are performed normally. |
121 | | static inline void BeginPassThroughThreadEvents(); |
122 | | static inline void EndPassThroughThreadEvents(); |
123 | | |
124 | | // Whether events in this thread are passed through. |
125 | | static inline bool AreThreadEventsPassedThrough(); |
126 | | |
127 | | // RAII class for regions where thread events are passed through. |
128 | | struct MOZ_RAII AutoPassThroughThreadEvents |
129 | | { |
130 | | AutoPassThroughThreadEvents() { BeginPassThroughThreadEvents(); } |
131 | | ~AutoPassThroughThreadEvents() { EndPassThroughThreadEvents(); } |
132 | | }; |
133 | | |
134 | | // As for AutoPassThroughThreadEvents, but may be used when events are already |
135 | | // passed through. |
136 | | struct MOZ_RAII AutoEnsurePassThroughThreadEvents |
137 | | { |
138 | | AutoEnsurePassThroughThreadEvents() |
139 | | : mPassedThrough(AreThreadEventsPassedThrough()) |
140 | | { |
141 | | if (!mPassedThrough) |
142 | | BeginPassThroughThreadEvents(); |
143 | | } |
144 | | |
145 | | ~AutoEnsurePassThroughThreadEvents() |
146 | | { |
147 | | if (!mPassedThrough) |
148 | | EndPassThroughThreadEvents(); |
149 | | } |
150 | | |
151 | | private: |
152 | | bool mPassedThrough; |
153 | | }; |
154 | | |
155 | | // Mark a region where thread events are not allowed to occur. The process will |
156 | | // crash immediately if an event does happen. |
157 | | static inline void BeginDisallowThreadEvents(); |
158 | | static inline void EndDisallowThreadEvents(); |
159 | | |
160 | | // Whether events in this thread are disallowed. |
161 | | static inline bool AreThreadEventsDisallowed(); |
162 | | |
163 | | // RAII class for a region where thread events are disallowed. |
164 | | struct MOZ_RAII AutoDisallowThreadEvents |
165 | | { |
166 | | AutoDisallowThreadEvents() { BeginDisallowThreadEvents(); } |
167 | | ~AutoDisallowThreadEvents() { EndDisallowThreadEvents(); } |
168 | | }; |
169 | | |
170 | | // Record or replay a value in the current thread's event stream. |
171 | | static inline size_t RecordReplayValue(size_t aValue); |
172 | | |
173 | | // Record or replay the contents of a range of memory in the current thread's |
174 | | // event stream. |
175 | | static inline void RecordReplayBytes(void* aData, size_t aSize); |
176 | | |
177 | | // During recording or replay, mark the recording as unusable. There are some |
178 | | // behaviors that can't be reliably recorded or replayed. For more information, |
179 | | // see 'Unrecordable Executions' in the URL above. |
180 | | static inline void InvalidateRecording(const char* aWhy); |
181 | | |
182 | | // API for ensuring deterministic recording and replaying of PLDHashTables. |
183 | | // This allows PLDHashTables to behave deterministically by generating a custom |
184 | | // set of operations for each table and requiring no other instrumentation. |
185 | | // (PLHashTables have a similar mechanism, though it is not exposed here.) |
186 | | static inline const PLDHashTableOps* GeneratePLDHashTableCallbacks(const PLDHashTableOps* aOps); |
187 | | static inline const PLDHashTableOps* UnwrapPLDHashTableCallbacks(const PLDHashTableOps* aOps); |
188 | | static inline void DestroyPLDHashTableCallbacks(const PLDHashTableOps* aOps); |
189 | | static inline void MovePLDHashTableContents(const PLDHashTableOps* aFirstOps, |
190 | | const PLDHashTableOps* aSecondOps); |
191 | | |
192 | | // Associate an arbitrary pointer with a JS object root while replaying. This |
193 | | // is useful for replaying the behavior of weak pointers. |
194 | | MFBT_API void SetWeakPointerJSRoot(const void* aPtr, JSObject* aJSObj); |
195 | | |
196 | | // API for ensuring that a function executes at a consistent point when |
197 | | // recording or replaying. This is primarily needed for finalizers and other |
198 | | // activity during a GC that can perform recorded events (because GCs can |
199 | | // occur at different times and behave differently between recording and |
200 | | // replay, thread events are disallowed during a GC). Triggers can be |
201 | | // registered at a point where thread events are allowed, then activated at |
202 | | // a point where thread events are not allowed. When recording, the trigger's |
203 | | // callback will execute at the next point when ExecuteTriggers is called on |
204 | | // the thread which originally registered the trigger (typically at the top of |
205 | | // the thread's event loop), and when replaying the callback will execute at |
206 | | // the same point, even if it was never activated. |
207 | | // |
208 | | // Below is an example of how this API can be used. |
209 | | // |
210 | | // // This structure's lifetime is managed by the GC. |
211 | | // struct GarbageCollectedHolder { |
212 | | // GarbageCollectedHolder() { |
213 | | // RegisterTrigger(this, [=]() { this->DestroyContents(); }); |
214 | | // } |
215 | | // ~GarbageCollectedHolder() { |
216 | | // UnregisterTrigger(this); |
217 | | // } |
218 | | // |
219 | | // void Finalize() { |
220 | | // // During finalization, thread events are disallowed. |
221 | | // if (IsRecordingOrReplaying()) { |
222 | | // ActivateTrigger(this); |
223 | | // } else { |
224 | | // DestroyContents(); |
225 | | // } |
226 | | // } |
227 | | // |
228 | | // // This is free to release resources held by the system, communicate with |
229 | | // // other threads or processes, and so forth. When replaying, this may |
230 | | // // be called before the GC has actually collected this object, but since |
231 | | // // the GC will have already collected this object at this point in the |
232 | | // // recording, this object will never be accessed again. |
233 | | // void DestroyContents(); |
234 | | // }; |
235 | | MFBT_API void RegisterTrigger(void* aObj, const std::function<void()>& aCallback); |
236 | | MFBT_API void UnregisterTrigger(void* aObj); |
237 | | MFBT_API void ActivateTrigger(void* aObj); |
238 | | MFBT_API void ExecuteTriggers(); |
239 | | |
240 | | // Some devtools operations which execute in a replaying process can cause code |
241 | | // to run which did not run while recording. For example, the JS debugger can |
242 | | // run arbitrary JS while paused at a breakpoint, by doing an eval(). In such |
243 | | // cases we say that execution has diverged from the recording, and if recorded |
244 | | // events are encountered the associated devtools operation fails. This API can |
245 | | // be used to test for such cases and avoid causing the operation to fail. |
246 | | static inline bool HasDivergedFromRecording(); |
247 | | |
248 | | // API for handling unrecorded waits. During replay, periodically all threads |
249 | | // must enter a specific idle state so that checkpoints may be saved or |
250 | | // restored for rewinding. For threads which block on recorded resources |
251 | | // --- they wait on a recorded lock (one which was created when events were not |
252 | | // passed through) or an associated cvar --- this is handled automatically. |
253 | | // |
254 | | // Threads which block indefinitely on unrecorded resources must call |
255 | | // NotifyUnrecordedWait first. |
256 | | // |
257 | | // The callback passed to NotifyUnrecordedWait will be invoked at most once |
258 | | // by the main thread whenever the main thread is waiting for other threads to |
259 | | // become idle, and at most once after the call to NotifyUnrecordedWait if the |
260 | | // main thread is already waiting for other threads to become idle. |
261 | | // |
262 | | // The callback should poke the thread so that it is no longer blocked on the |
263 | | // resource. The thread must call MaybeWaitForCheckpointSave before blocking |
264 | | // again. |
265 | | MFBT_API void NotifyUnrecordedWait(const std::function<void()>& aCallback); |
266 | | MFBT_API void MaybeWaitForCheckpointSave(); |
267 | | |
268 | | // API for debugging inconsistent behavior between recording and replay. |
269 | | // By calling Assert or AssertBytes a thread event will be inserted and any |
270 | | // inconsistent execution order of events will be detected (as for normal |
271 | | // thread events) and reported to the console. |
272 | | // |
273 | | // RegisterThing/UnregisterThing associate arbitrary pointers with indexes that |
274 | | // will be consistent between recording/replaying and can be used in assertion |
275 | | // strings. |
276 | | static inline void RecordReplayAssert(const char* aFormat, ...); |
277 | | static inline void RecordReplayAssertBytes(const void* aData, size_t aSize); |
278 | | static inline void RegisterThing(void* aThing); |
279 | | static inline void UnregisterThing(void* aThing); |
280 | | static inline size_t ThingIndex(void* aThing); |
281 | | |
282 | | // Give a directive to the record/replay system. For possible values for |
283 | | // aDirective, see ProcessRecordReplay.h. This is used for testing purposes. |
284 | | static inline void RecordReplayDirective(long aDirective); |
285 | | |
286 | | // Helper for record/replay asserts, try to determine a name for a C++ object |
287 | | // with virtual methods based on its vtable. |
288 | | static inline const char* VirtualThingName(void* aThing); |
289 | | |
290 | | // Enum which describes whether to preserve behavior between recording and |
291 | | // replay sessions. |
292 | | enum class Behavior { |
293 | | DontPreserve, |
294 | | Preserve |
295 | | }; |
296 | | |
297 | | // Determine whether this is a recording/replaying or middleman process, and |
298 | | // initialize record/replay state if so. |
299 | | MFBT_API void Initialize(int aArgc, char* aArgv[]); |
300 | | |
301 | | // Kinds of recording/replaying processes that can be spawned. |
302 | | enum class ProcessKind { |
303 | | Recording, |
304 | | Replaying, |
305 | | MiddlemanRecording, |
306 | | MiddlemanReplaying |
307 | | }; |
308 | | |
309 | | // Command line option for specifying the record/replay kind of a process. |
310 | | static const char gProcessKindOption[] = "-recordReplayKind"; |
311 | | |
312 | | // Command line option for specifying the recording file to use. |
313 | | static const char gRecordingFileOption[] = "-recordReplayFile"; |
314 | | |
315 | | /////////////////////////////////////////////////////////////////////////////// |
316 | | // JS interface |
317 | | /////////////////////////////////////////////////////////////////////////////// |
318 | | |
319 | | // Get the counter used to keep track of how much progress JS execution has |
320 | | // made while running on the main thread. Progress must advance whenever a JS |
321 | | // function is entered or loop entry point is reached, so that no script |
322 | | // location may be hit twice while the progress counter is the same. See |
323 | | // JSControl.h for more. |
324 | | typedef uint64_t ProgressCounter; |
325 | | MFBT_API ProgressCounter* ExecutionProgressCounter(); |
326 | | |
327 | | static inline void |
328 | | AdvanceExecutionProgressCounter() |
329 | 0 | { |
330 | 0 | ++*ExecutionProgressCounter(); |
331 | 0 | } |
332 | | |
333 | | // Get an identifier for the current execution point which can be used to warp |
334 | | // here later. |
335 | | MFBT_API ProgressCounter NewTimeWarpTarget(); |
336 | | |
337 | | // Return whether a script is internal to the record/replay infrastructure, |
338 | | // may run non-deterministically between recording and replaying, and whose |
339 | | // execution must not update the progress counter. |
340 | | MFBT_API bool IsInternalScript(const char* aURL); |
341 | | |
342 | | // Define a RecordReplayControl object on the specified global object, with |
343 | | // methods specialized to the current recording/replaying or middleman process |
344 | | // kind. |
345 | | MFBT_API bool DefineRecordReplayControlObject(JSContext* aCx, JSObject* aObj); |
346 | | |
347 | | // Notify the infrastructure that some URL which contains JavaScript is |
348 | | // being parsed. This is used to provide the complete contents of the URL to |
349 | | // devtools code when it is inspecting the state of this process; that devtools |
350 | | // code can't simply fetch the URL itself since it may have been changed since |
351 | | // the recording was made or may no longer exist. The token for a parse may not |
352 | | // be used in other parses until after EndContentParse() is called. |
353 | | MFBT_API void BeginContentParse(const void* aToken, |
354 | | const char* aURL, const char* aContentType); |
355 | | |
356 | | // Add some parse data to an existing content parse. |
357 | | MFBT_API void AddContentParseData(const void* aToken, |
358 | | const char16_t* aBuffer, size_t aLength); |
359 | | |
360 | | // Mark a content parse as having completed. |
361 | | MFBT_API void EndContentParse(const void* aToken); |
362 | | |
363 | | // Perform an entire content parse, when the entire URL is available at once. |
364 | | static inline void |
365 | | NoteContentParse(const void* aToken, |
366 | | const char* aURL, const char* aContentType, |
367 | | const char16_t* aBuffer, size_t aLength) |
368 | 0 | { |
369 | 0 | BeginContentParse(aToken, aURL, aContentType); |
370 | 0 | AddContentParseData(aToken, aBuffer, aLength); |
371 | 0 | EndContentParse(aToken); |
372 | 0 | } |
373 | | |
374 | | /////////////////////////////////////////////////////////////////////////////// |
375 | | // API inline function implementation |
376 | | /////////////////////////////////////////////////////////////////////////////// |
377 | | |
378 | | // Define inline wrappers on builds where recording/replaying is enabled. |
379 | | #if defined(XP_MACOSX) && defined(NIGHTLY_BUILD) |
380 | | |
381 | | #define MOZ_MakeRecordReplayWrapperVoid(aName, aFormals, aActuals) \ |
382 | | MFBT_API void Internal ##aName aFormals; \ |
383 | | static inline void aName aFormals \ |
384 | | { \ |
385 | | if (IsRecordingOrReplaying()) { \ |
386 | | Internal ##aName aActuals; \ |
387 | | } \ |
388 | | } |
389 | | |
390 | | #define MOZ_MakeRecordReplayWrapper(aName, aReturnType, aDefaultValue, aFormals, aActuals) \ |
391 | | MFBT_API aReturnType Internal ##aName aFormals; \ |
392 | | static inline aReturnType aName aFormals \ |
393 | | { \ |
394 | | if (IsRecordingOrReplaying()) { \ |
395 | | return Internal ##aName aActuals; \ |
396 | | } \ |
397 | | return aDefaultValue; \ |
398 | | } |
399 | | |
400 | | // Define inline wrappers on other builds. Avoiding references to the out of |
401 | | // line method avoids link errors when e.g. using Atomic<> but not linking |
402 | | // against MFBT. |
403 | | #else |
404 | | |
405 | | #define MOZ_MakeRecordReplayWrapperVoid(aName, aFormals, aActuals) \ |
406 | 0 | static inline void aName aFormals {} Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::BeginOrderedAtomicAccess() Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::EndOrderedAtomicAccess() Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::BeginPassThroughThreadEvents() Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::EndPassThroughThreadEvents() Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::BeginDisallowThreadEvents() Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::EndDisallowThreadEvents() Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::RecordReplayBytes(void*, unsigned long) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::DestroyPLDHashTableCallbacks(PLDHashTableOps const*) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::MovePLDHashTableContents(PLDHashTableOps const*, PLDHashTableOps const*) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::InvalidateRecording(char const*) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::RegisterWeakPointer(void const*, std::__1::function<void (bool)> const&) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::UnregisterWeakPointer(void const*) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::WeakPointerAccess(void const*, bool) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::RecordReplayAssertBytes(void const*, unsigned long) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::RegisterThing(void*) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::UnregisterThing(void*) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::RecordReplayDirective(long) |
407 | | |
408 | | #define MOZ_MakeRecordReplayWrapper(aName, aReturnType, aDefaultValue, aFormals, aActuals) \ |
409 | 0 | static inline aReturnType aName aFormals { return aDefaultValue; } Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::AreThreadEventsPassedThrough() Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::AreThreadEventsDisallowed() Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::RecordReplayValue(unsigned long) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::HasDivergedFromRecording() Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::GeneratePLDHashTableCallbacks(PLDHashTableOps const*) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::UnwrapPLDHashTableCallbacks(PLDHashTableOps const*) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::ThingIndex(void*) Unexecuted instantiation: Unified_cpp_mfbt0.cpp:mozilla::recordreplay::VirtualThingName(void*) |
410 | | |
411 | | #endif |
412 | | |
413 | | MOZ_MakeRecordReplayWrapperVoid(BeginOrderedAtomicAccess, (), ()) |
414 | | MOZ_MakeRecordReplayWrapperVoid(EndOrderedAtomicAccess, (), ()) |
415 | | MOZ_MakeRecordReplayWrapperVoid(BeginPassThroughThreadEvents, (), ()) |
416 | | MOZ_MakeRecordReplayWrapperVoid(EndPassThroughThreadEvents, (), ()) |
417 | | MOZ_MakeRecordReplayWrapper(AreThreadEventsPassedThrough, bool, false, (), ()) |
418 | | MOZ_MakeRecordReplayWrapperVoid(BeginDisallowThreadEvents, (), ()) |
419 | | MOZ_MakeRecordReplayWrapperVoid(EndDisallowThreadEvents, (), ()) |
420 | | MOZ_MakeRecordReplayWrapper(AreThreadEventsDisallowed, bool, false, (), ()) |
421 | | MOZ_MakeRecordReplayWrapper(RecordReplayValue, size_t, aValue, (size_t aValue), (aValue)) |
422 | | MOZ_MakeRecordReplayWrapperVoid(RecordReplayBytes, (void* aData, size_t aSize), (aData, aSize)) |
423 | | MOZ_MakeRecordReplayWrapper(HasDivergedFromRecording, bool, false, (), ()) |
424 | | MOZ_MakeRecordReplayWrapper(GeneratePLDHashTableCallbacks, |
425 | | const PLDHashTableOps*, aOps, (const PLDHashTableOps* aOps), (aOps)) |
426 | | MOZ_MakeRecordReplayWrapper(UnwrapPLDHashTableCallbacks, |
427 | | const PLDHashTableOps*, aOps, (const PLDHashTableOps* aOps), (aOps)) |
428 | | MOZ_MakeRecordReplayWrapperVoid(DestroyPLDHashTableCallbacks, |
429 | | (const PLDHashTableOps* aOps), (aOps)) |
430 | | MOZ_MakeRecordReplayWrapperVoid(MovePLDHashTableContents, |
431 | | (const PLDHashTableOps* aFirstOps, |
432 | | const PLDHashTableOps* aSecondOps), |
433 | | (aFirstOps, aSecondOps)) |
434 | | MOZ_MakeRecordReplayWrapperVoid(InvalidateRecording, (const char* aWhy), (aWhy)) |
435 | | MOZ_MakeRecordReplayWrapperVoid(RegisterWeakPointer, |
436 | | (const void* aPtr, const std::function<void(bool)>& aCallback), |
437 | | (aPtr, aCallback)) |
438 | | MOZ_MakeRecordReplayWrapperVoid(UnregisterWeakPointer, (const void* aPtr), (aPtr)) |
439 | | MOZ_MakeRecordReplayWrapperVoid(WeakPointerAccess, |
440 | | (const void* aPtr, bool aSuccess), (aPtr, aSuccess)) |
441 | | MOZ_MakeRecordReplayWrapperVoid(RecordReplayAssertBytes, |
442 | | (const void* aData, size_t aSize), (aData, aSize)) |
443 | | MOZ_MakeRecordReplayWrapperVoid(RegisterThing, (void* aThing), (aThing)) |
444 | | MOZ_MakeRecordReplayWrapperVoid(UnregisterThing, (void* aThing), (aThing)) |
445 | | MOZ_MakeRecordReplayWrapper(ThingIndex, size_t, 0, (void* aThing), (aThing)) |
446 | | MOZ_MakeRecordReplayWrapper(VirtualThingName, const char*, nullptr, (void* aThing), (aThing)) |
447 | | MOZ_MakeRecordReplayWrapperVoid(RecordReplayDirective, (long aDirective), (aDirective)) |
448 | | |
449 | | #undef MOZ_MakeRecordReplayWrapperVoid |
450 | | #undef MOZ_MakeRecordReplayWrapper |
451 | | |
452 | | MFBT_API void InternalRecordReplayAssert(const char* aFormat, va_list aArgs); |
453 | | |
454 | | static inline void |
455 | | RecordReplayAssert(const char* aFormat, ...) |
456 | 0 | { |
457 | 0 | if (IsRecordingOrReplaying()) { |
458 | 0 | va_list ap; |
459 | 0 | va_start(ap, aFormat); |
460 | 0 | InternalRecordReplayAssert(aFormat, ap); |
461 | 0 | va_end(ap); |
462 | 0 | } |
463 | 0 | } |
464 | | |
465 | | } // recordreplay |
466 | | } // mozilla |
467 | | |
468 | | #endif /* mozilla_RecordReplay_h */ |