Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/mfbt/RecordReplay.cpp
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
#include "RecordReplay.h"
8
9
#include "js/GCAnnotations.h"
10
#include "mozilla/Atomics.h"
11
#include "mozilla/Casting.h"
12
13
#include <stdlib.h>
14
15
// Recording and replaying is only enabled on Mac nightlies.
16
#if defined(XP_MACOSX) && defined(NIGHTLY_BUILD)
17
#define ENABLE_RECORD_REPLAY
18
#endif
19
20
#ifdef ENABLE_RECORD_REPLAY
21
#include <dlfcn.h>
22
#endif
23
24
namespace mozilla {
25
namespace recordreplay {
26
27
#define FOR_EACH_INTERFACE(Macro)                               \
28
0
  Macro(InternalAreThreadEventsPassedThrough, bool, (), ())     \
29
0
  Macro(InternalAreThreadEventsDisallowed, bool, (), ())        \
30
0
  Macro(InternalRecordReplayValue, size_t, (size_t aValue), (aValue)) \
31
0
  Macro(InternalHasDivergedFromRecording, bool, (), ())         \
32
0
  Macro(InternalGeneratePLDHashTableCallbacks, const PLDHashTableOps*, \
33
0
        (const PLDHashTableOps* aOps), (aOps))                  \
34
0
  Macro(InternalUnwrapPLDHashTableCallbacks, const PLDHashTableOps*, \
35
0
        (const PLDHashTableOps* aOps), (aOps))                  \
36
0
  Macro(InternalThingIndex, size_t, (void* aThing), (aThing))   \
37
0
  Macro(InternalVirtualThingName, const char*, (void* aThing), (aThing)) \
38
0
  Macro(ExecutionProgressCounter, ProgressCounter*, (), ())     \
39
0
  Macro(NewTimeWarpTarget, ProgressCounter, (), ())             \
40
0
  Macro(IsInternalScript, bool, (const char* aURL), (aURL))     \
41
0
  Macro(DefineRecordReplayControlObject, bool, (JSContext* aCx, JSObject* aObj), (aCx, aObj))
42
43
#define FOR_EACH_INTERFACE_VOID(Macro)                          \
44
0
  Macro(InternalBeginOrderedAtomicAccess, (), ())               \
45
0
  Macro(InternalEndOrderedAtomicAccess, (), ())                 \
46
0
  Macro(InternalBeginPassThroughThreadEvents, (), ())           \
47
0
  Macro(InternalEndPassThroughThreadEvents, (), ())             \
48
0
  Macro(InternalBeginDisallowThreadEvents, (), ())              \
49
0
  Macro(InternalEndDisallowThreadEvents, (), ())                \
50
0
  Macro(InternalRecordReplayBytes,                              \
51
0
        (void* aData, size_t aSize), (aData, aSize))            \
52
0
  Macro(NotifyUnrecordedWait,                                   \
53
0
        (const std::function<void()>& aCallback), (aCallback))  \
54
0
  Macro(MaybeWaitForCheckpointSave, (), ())                     \
55
0
  Macro(InternalInvalidateRecording, (const char* aWhy), (aWhy)) \
56
0
  Macro(InternalDestroyPLDHashTableCallbacks,                   \
57
0
        (const PLDHashTableOps* aOps), (aOps))                  \
58
0
  Macro(InternalMovePLDHashTableContents,                       \
59
0
        (const PLDHashTableOps* aFirstOps, const PLDHashTableOps* aSecondOps), \
60
0
        (aFirstOps, aSecondOps))                                \
61
0
  Macro(SetWeakPointerJSRoot,                                   \
62
0
        (const void* aPtr, JSObject* aJSObj), (aPtr, aJSObj))   \
63
0
  Macro(RegisterTrigger,                                        \
64
0
        (void* aObj, const std::function<void()>& aCallback),   \
65
0
        (aObj, aCallback))                                      \
66
0
  Macro(UnregisterTrigger,                                      \
67
0
        (void* aObj), (aObj))                                   \
68
0
  Macro(ActivateTrigger, (void* aObj), (aObj))                  \
69
0
  Macro(ExecuteTriggers, (), ())                                \
70
0
  Macro(InternalRecordReplayAssert, (const char* aFormat, va_list aArgs), (aFormat, aArgs)) \
71
0
  Macro(InternalRecordReplayAssertBytes,                        \
72
0
        (const void* aData, size_t aSize), (aData, aSize))      \
73
0
  Macro(InternalRegisterThing, (void* aThing), (aThing))        \
74
0
  Macro(InternalUnregisterThing, (void* aThing), (aThing))      \
75
0
  Macro(InternalRecordReplayDirective, (long aDirective), (aDirective)) \
76
0
  Macro(BeginContentParse,                                      \
77
0
        (const void* aToken, const char* aURL, const char* aContentType), \
78
0
        (aToken, aURL, aContentType))                           \
79
0
  Macro(AddContentParseData,                                    \
80
0
        (const void* aToken, const char16_t* aBuffer, size_t aLength), \
81
0
        (aToken, aBuffer, aLength))                             \
82
0
  Macro(EndContentParse, (const void* aToken), (aToken))
83
84
#define DECLARE_SYMBOL(aName, aReturnType, aFormals, _) \
85
  static aReturnType (*gPtr ##aName) aFormals;
86
#define DECLARE_SYMBOL_VOID(aName, aFormals, _)  DECLARE_SYMBOL(aName, void, aFormals, _)
87
88
FOR_EACH_INTERFACE(DECLARE_SYMBOL)
89
FOR_EACH_INTERFACE_VOID(DECLARE_SYMBOL_VOID)
90
91
#undef DECLARE_SYMBOL
92
#undef DECLARE_SYMBOL_VOID
93
94
static void*
95
LoadSymbol(const char* aName)
96
0
{
97
#ifdef ENABLE_RECORD_REPLAY
98
  void* rv = dlsym(RTLD_DEFAULT, aName);
99
  MOZ_RELEASE_ASSERT(rv);
100
  return rv;
101
#else
102
  return nullptr;
103
0
#endif
104
0
}
105
106
void
107
Initialize(int aArgc, char* aArgv[])
108
0
{
109
0
  // Only initialize if the right command line option was specified.
110
0
  bool found = false;
111
0
  for (int i = 0; i < aArgc; i++) {
112
0
    if (!strcmp(aArgv[i], gProcessKindOption)) {
113
0
      found = true;
114
0
      break;
115
0
    }
116
0
  }
117
0
  if (!found) {
118
0
    return;
119
0
  }
120
0
121
0
  void (*initialize)(int, char**);
122
0
  BitwiseCast(LoadSymbol("RecordReplayInterface_Initialize"), &initialize);
123
0
  if (!initialize) {
124
0
    return;
125
0
  }
126
0
127
0
#define INIT_SYMBOL(aName, _1, _2, _3)                                  \
128
0
  BitwiseCast(LoadSymbol("RecordReplayInterface_" #aName), &gPtr ##aName);
129
0
#define INIT_SYMBOL_VOID(aName, _2, _3)  INIT_SYMBOL(aName, void, _2, _3)
130
0
131
0
FOR_EACH_INTERFACE(INIT_SYMBOL)
132
0
FOR_EACH_INTERFACE_VOID(INIT_SYMBOL_VOID)
133
0
134
0
#undef INIT_SYMBOL
135
0
#undef INIT_SYMBOL_VOID
136
0
137
0
  initialize(aArgc, aArgv);
138
0
}
139
140
// Record/replay API functions can't GC, but we can't use
141
// JS::AutoSuppressGCAnalysis here due to linking issues.
142
struct AutoSuppressGCAnalysis
143
{
144
0
  AutoSuppressGCAnalysis() {}
145
0
  ~AutoSuppressGCAnalysis() {
146
#ifdef DEBUG
147
    // Need nontrivial destructor.
148
    static Atomic<int, SequentiallyConsistent, Behavior::DontPreserve> dummy;
149
    dummy++;
150
#endif
151
  }
152
} JS_HAZ_GC_SUPPRESSED;
153
154
#define DEFINE_WRAPPER(aName, aReturnType, aFormals, aActuals)  \
155
  aReturnType aName aFormals                                    \
156
0
  {                                                             \
157
0
    AutoSuppressGCAnalysis suppress;                            \
158
0
    MOZ_ASSERT(IsRecordingOrReplaying() || IsMiddleman());      \
159
0
    return gPtr ##aName aActuals;                               \
160
0
  }
Unexecuted instantiation: mozilla::recordreplay::InternalAreThreadEventsPassedThrough()
Unexecuted instantiation: mozilla::recordreplay::InternalAreThreadEventsDisallowed()
Unexecuted instantiation: mozilla::recordreplay::InternalRecordReplayValue(unsigned long)
Unexecuted instantiation: mozilla::recordreplay::InternalHasDivergedFromRecording()
Unexecuted instantiation: mozilla::recordreplay::InternalGeneratePLDHashTableCallbacks(PLDHashTableOps const*)
Unexecuted instantiation: mozilla::recordreplay::InternalUnwrapPLDHashTableCallbacks(PLDHashTableOps const*)
Unexecuted instantiation: mozilla::recordreplay::InternalThingIndex(void*)
Unexecuted instantiation: mozilla::recordreplay::InternalVirtualThingName(void*)
Unexecuted instantiation: mozilla::recordreplay::ExecutionProgressCounter()
Unexecuted instantiation: mozilla::recordreplay::NewTimeWarpTarget()
Unexecuted instantiation: mozilla::recordreplay::IsInternalScript(char const*)
Unexecuted instantiation: mozilla::recordreplay::DefineRecordReplayControlObject(JSContext*, JSObject*)
161
162
#define DEFINE_WRAPPER_VOID(aName, aFormals, aActuals)          \
163
  void aName aFormals                                           \
164
0
  {                                                             \
165
0
    AutoSuppressGCAnalysis suppress;                            \
166
0
    MOZ_ASSERT(IsRecordingOrReplaying() || IsMiddleman());      \
167
0
    gPtr ##aName aActuals;                                      \
168
0
  }
Unexecuted instantiation: mozilla::recordreplay::InternalBeginOrderedAtomicAccess()
Unexecuted instantiation: mozilla::recordreplay::InternalEndOrderedAtomicAccess()
Unexecuted instantiation: mozilla::recordreplay::InternalBeginPassThroughThreadEvents()
Unexecuted instantiation: mozilla::recordreplay::InternalEndPassThroughThreadEvents()
Unexecuted instantiation: mozilla::recordreplay::InternalBeginDisallowThreadEvents()
Unexecuted instantiation: mozilla::recordreplay::InternalEndDisallowThreadEvents()
Unexecuted instantiation: mozilla::recordreplay::InternalRecordReplayBytes(void*, unsigned long)
Unexecuted instantiation: mozilla::recordreplay::NotifyUnrecordedWait(std::__1::function<void ()> const&)
Unexecuted instantiation: mozilla::recordreplay::MaybeWaitForCheckpointSave()
Unexecuted instantiation: mozilla::recordreplay::InternalInvalidateRecording(char const*)
Unexecuted instantiation: mozilla::recordreplay::InternalDestroyPLDHashTableCallbacks(PLDHashTableOps const*)
Unexecuted instantiation: mozilla::recordreplay::InternalMovePLDHashTableContents(PLDHashTableOps const*, PLDHashTableOps const*)
Unexecuted instantiation: mozilla::recordreplay::SetWeakPointerJSRoot(void const*, JSObject*)
Unexecuted instantiation: mozilla::recordreplay::RegisterTrigger(void*, std::__1::function<void ()> const&)
Unexecuted instantiation: mozilla::recordreplay::UnregisterTrigger(void*)
Unexecuted instantiation: mozilla::recordreplay::ActivateTrigger(void*)
Unexecuted instantiation: mozilla::recordreplay::ExecuteTriggers()
Unexecuted instantiation: mozilla::recordreplay::InternalRecordReplayAssert(char const*, __va_list_tag*)
Unexecuted instantiation: mozilla::recordreplay::InternalRecordReplayAssertBytes(void const*, unsigned long)
Unexecuted instantiation: mozilla::recordreplay::InternalRegisterThing(void*)
Unexecuted instantiation: mozilla::recordreplay::InternalUnregisterThing(void*)
Unexecuted instantiation: mozilla::recordreplay::InternalRecordReplayDirective(long)
Unexecuted instantiation: mozilla::recordreplay::BeginContentParse(void const*, char const*, char const*)
Unexecuted instantiation: mozilla::recordreplay::AddContentParseData(void const*, char16_t const*, unsigned long)
Unexecuted instantiation: mozilla::recordreplay::EndContentParse(void const*)
169
170
FOR_EACH_INTERFACE(DEFINE_WRAPPER)
171
FOR_EACH_INTERFACE_VOID(DEFINE_WRAPPER_VOID)
172
173
#undef DEFINE_WRAPPER
174
#undef DEFINE_WRAPPER_VOID
175
176
#ifdef ENABLE_RECORD_REPLAY
177
178
bool gIsRecordingOrReplaying;
179
bool gIsRecording;
180
bool gIsReplaying;
181
bool gIsMiddleman;
182
183
#endif // ENABLE_RECORD_REPLAY
184
185
#undef ENABLE_RECORD_REPLAY
186
187
} // recordreplay
188
} // mozilla