Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/js/TracingAPI.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
 * vim: set ts=8 sts=4 et sw=4 tw=99:
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
#ifndef js_TracingAPI_h
8
#define js_TracingAPI_h
9
10
#include "js/AllocPolicy.h"
11
#include "js/HashTable.h"
12
#include "js/HeapAPI.h"
13
#include "js/TraceKind.h"
14
15
class JS_PUBLIC_API(JSTracer);
16
17
namespace JS {
18
class JS_PUBLIC_API(CallbackTracer);
19
template <typename T> class Heap;
20
template <typename T> class TenuredHeap;
21
22
/** Returns a static string equivalent of |kind|. */
23
JS_FRIEND_API(const char*)
24
GCTraceKindToAscii(JS::TraceKind kind);
25
26
} // namespace JS
27
28
enum WeakMapTraceKind {
29
    /**
30
     * Do not trace into weak map keys or values during traversal. Users must
31
     * handle weak maps manually.
32
     */
33
    DoNotTraceWeakMaps,
34
35
    /**
36
     * Do true ephemeron marking with a weak key lookup marking phase. This is
37
     * the default for GCMarker.
38
     */
39
    ExpandWeakMaps,
40
41
    /**
42
     * Trace through to all values, irrespective of whether the keys are live
43
     * or not. Used for non-marking tracers.
44
     */
45
    TraceWeakMapValues,
46
47
    /**
48
     * Trace through to all keys and values, irrespective of whether the keys
49
     * are live or not. Used for non-marking tracers.
50
     */
51
    TraceWeakMapKeysValues
52
};
53
54
class JS_PUBLIC_API(JSTracer)
55
{
56
  public:
57
    // Return the runtime set on the tracer.
58
    JSRuntime* runtime() const { return runtime_; }
59
60
    // Return the weak map tracing behavior currently set on this tracer.
61
    WeakMapTraceKind weakMapAction() const { return weakMapAction_; }
62
63
    enum class TracerKindTag {
64
        // Marking path: a tracer used only for marking liveness of cells, not
65
        // for moving them. The kind will transition to WeakMarking after
66
        // everything reachable by regular edges has been marked.
67
        Marking,
68
69
        // Same as Marking, except we have now moved on to the "weak marking
70
        // phase", in which every marked obj/script is immediately looked up to
71
        // see if it is a weak map key (and therefore might require marking its
72
        // weak map value).
73
        WeakMarking,
74
75
        // A tracer that traverses the graph for the purposes of moving objects
76
        // from the nursery to the tenured area.
77
        Tenuring,
78
79
        // General-purpose traversal that invokes a callback on each cell.
80
        // Traversing children is the responsibility of the callback.
81
        Callback
82
    };
83
    bool isMarkingTracer() const { return tag_ == TracerKindTag::Marking || tag_ == TracerKindTag::WeakMarking; }
84
    bool isWeakMarkingTracer() const { return tag_ == TracerKindTag::WeakMarking; }
85
    bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; }
86
    bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; }
87
    inline JS::CallbackTracer* asCallbackTracer();
88
0
    bool traceWeakEdges() const { return traceWeakEdges_; }
89
0
    bool canSkipJsids() const { return canSkipJsids_; }
90
#ifdef DEBUG
91
    bool checkEdges() { return checkEdges_; }
92
#endif
93
94
    // Get the current GC number. Only call this method if |isMarkingTracer()|
95
    // is true.
96
    uint32_t gcNumberForMarking() const;
97
98
  protected:
99
    JSTracer(JSRuntime* rt, TracerKindTag tag,
100
             WeakMapTraceKind weakTraceKind = TraceWeakMapValues)
101
      : runtime_(rt)
102
      , weakMapAction_(weakTraceKind)
103
#ifdef DEBUG
104
      , checkEdges_(true)
105
#endif
106
      , tag_(tag)
107
      , traceWeakEdges_(true)
108
      , canSkipJsids_(false)
109
0
    {}
110
111
#ifdef DEBUG
112
    // Set whether to check edges are valid in debug builds.
113
    void setCheckEdges(bool check) {
114
        checkEdges_ = check;
115
    }
116
#endif
117
118
  private:
119
    JSRuntime* runtime_;
120
    WeakMapTraceKind weakMapAction_;
121
#ifdef DEBUG
122
    bool checkEdges_;
123
#endif
124
125
  protected:
126
    TracerKindTag tag_;
127
    bool traceWeakEdges_;
128
    bool canSkipJsids_;
129
};
130
131
namespace JS {
132
133
class AutoTracingName;
134
class AutoTracingIndex;
135
class AutoTracingCallback;
136
137
class JS_PUBLIC_API(CallbackTracer) : public JSTracer
138
{
139
  public:
140
    CallbackTracer(JSRuntime* rt, WeakMapTraceKind weakTraceKind = TraceWeakMapValues)
141
      : JSTracer(rt, JSTracer::TracerKindTag::Callback, weakTraceKind),
142
        contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr)
143
0
    {}
144
    CallbackTracer(JSContext* cx, WeakMapTraceKind weakTraceKind = TraceWeakMapValues);
145
146
    // Override these methods to receive notification when an edge is visited
147
    // with the type contained in the callback. The default implementation
148
    // dispatches to the fully-generic onChild implementation, so for cases that
149
    // do not care about boxing overhead and do not need the actual edges,
150
    // just override the generic onChild.
151
0
    virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); }
152
0
    virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); }
153
0
    virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); }
154
#ifdef ENABLE_BIGINT
155
    virtual void onBigIntEdge(JS::BigInt** bip) { onChild(JS::GCCellPtr(*bip)); }
156
#endif
157
0
    virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); }
158
0
    virtual void onShapeEdge(js::Shape** shapep) {
159
0
        onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape));
160
0
    }
161
0
    virtual void onObjectGroupEdge(js::ObjectGroup** groupp) {
162
0
        onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup));
163
0
    }
164
0
    virtual void onBaseShapeEdge(js::BaseShape** basep) {
165
0
        onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape));
166
0
    }
167
0
    virtual void onJitCodeEdge(js::jit::JitCode** codep) {
168
0
        onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode));
169
0
    }
170
0
    virtual void onLazyScriptEdge(js::LazyScript** lazyp) {
171
0
        onChild(JS::GCCellPtr(*lazyp, JS::TraceKind::LazyScript));
172
0
    }
173
0
    virtual void onScopeEdge(js::Scope** scopep) {
174
0
        onChild(JS::GCCellPtr(*scopep, JS::TraceKind::Scope));
175
0
    }
176
0
    virtual void onRegExpSharedEdge(js::RegExpShared** sharedp) {
177
0
        onChild(JS::GCCellPtr(*sharedp, JS::TraceKind::RegExpShared));
178
0
    }
179
180
    // Override this method to receive notification when a node in the GC
181
    // heap graph is visited.
182
    virtual void onChild(const JS::GCCellPtr& thing) = 0;
183
184
    // Access to the tracing context:
185
    // When tracing with a JS::CallbackTracer, we invoke the callback with the
186
    // edge location and the type of target. This is useful for operating on
187
    // the edge in the abstract or on the target thing, satisfying most common
188
    // use cases.  However, some tracers need additional detail about the
189
    // specific edge that is being traced in order to be useful. Unfortunately,
190
    // the raw pointer to the edge that we provide is not enough information to
191
    // infer much of anything useful about that edge.
192
    //
193
    // In order to better support use cases that care in particular about edges
194
    // -- as opposed to the target thing -- tracing implementations are
195
    // responsible for providing extra context information about each edge they
196
    // trace, as it is traced. This contains, at a minimum, an edge name and,
197
    // when tracing an array, the index. Further specialization can be achived
198
    // (with some complexity), by associating a functor with the tracer so
199
    // that, when requested, the user can generate totally custom edge
200
    // descriptions.
201
202
    // Returns the current edge's name. It is only valid to call this when
203
    // inside the trace callback, however, the edge name will always be set.
204
0
    const char* contextName() const { MOZ_ASSERT(contextName_); return contextName_; }
205
206
    // Returns the current edge's index, if marked as part of an array of edges.
207
    // This must be called only inside the trace callback. When not tracing an
208
    // array, the value will be InvalidIndex.
209
    const static size_t InvalidIndex = size_t(-1);
210
0
    size_t contextIndex() const { return contextIndex_; }
211
212
    // Build a description of this edge in the heap graph. This call may invoke
213
    // the context functor, if set, which may inspect arbitrary areas of the
214
    // heap. On the other hand, the description provided by this method may be
215
    // substantially more accurate and useful than those provided by only the
216
    // contextName and contextIndex.
217
    void getTracingEdgeName(char* buffer, size_t bufferSize);
218
219
    // The trace implementation may associate a callback with one or more edges
220
    // using AutoTracingDetails. This functor is called by getTracingEdgeName
221
    // and is responsible for providing a textual representation of the
222
    // currently being traced edge. The callback has access to the full heap,
223
    // including the currently set tracing context.
224
    class ContextFunctor {
225
      public:
226
        virtual void operator()(CallbackTracer* trc, char* buf, size_t bufsize) = 0;
227
    };
228
229
#ifdef DEBUG
230
    enum class TracerKind {
231
        DoNotCare,
232
        Moving,
233
        GrayBuffering,
234
        VerifyTraceProtoAndIface,
235
        ClearEdges,
236
        UnmarkGray
237
    };
238
    virtual TracerKind getTracerKind() const { return TracerKind::DoNotCare; }
239
#endif
240
241
    // In C++, overriding a method hides all methods in the base class with
242
    // that name, not just methods with that signature. Thus, the typed edge
243
    // methods have to have distinct names to allow us to override them
244
    // individually, which is freqently useful if, for example, we only want to
245
    // process only one type of edge.
246
0
    void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); }
247
0
    void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); }
248
0
    void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); }
249
#ifdef ENABLE_BIGINT
250
    void dispatchToOnEdge(JS::BigInt** bip) { onBigIntEdge(bip); }
251
#endif
252
0
    void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); }
253
0
    void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); }
254
0
    void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); }
255
0
    void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); }
256
0
    void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); }
257
0
    void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); }
258
0
    void dispatchToOnEdge(js::Scope** scopep) { onScopeEdge(scopep); }
259
0
    void dispatchToOnEdge(js::RegExpShared** sharedp) { onRegExpSharedEdge(sharedp); }
260
261
  protected:
262
0
    void setTraceWeakEdges(bool value) {
263
0
        traceWeakEdges_ = value;
264
0
    }
265
266
    // If this is set to false, then the tracer will skip some jsids
267
    // to improve performance. This is needed for the cycle collector.
268
0
    void setCanSkipJsids(bool value) {
269
0
        canSkipJsids_ = value;
270
0
    }
271
272
  private:
273
    friend class AutoTracingName;
274
    const char* contextName_;
275
276
    friend class AutoTracingIndex;
277
    size_t contextIndex_;
278
279
    friend class AutoTracingDetails;
280
    ContextFunctor* contextFunctor_;
281
};
282
283
// Set the name portion of the tracer's context for the current edge.
284
class MOZ_RAII AutoTracingName
285
{
286
    CallbackTracer* trc_;
287
    const char* prior_;
288
289
  public:
290
126
    AutoTracingName(CallbackTracer* trc, const char* name) : trc_(trc), prior_(trc->contextName_) {
291
126
        MOZ_ASSERT(name);
292
126
        trc->contextName_ = name;
293
126
    }
294
126
    ~AutoTracingName() {
295
126
        MOZ_ASSERT(trc_->contextName_);
296
126
        trc_->contextName_ = prior_;
297
126
    }
298
};
299
300
// Set the index portion of the tracer's context for the current range.
301
class MOZ_RAII AutoTracingIndex
302
{
303
    CallbackTracer* trc_;
304
305
  public:
306
4.59k
    explicit AutoTracingIndex(JSTracer* trc, size_t initial = 0) : trc_(nullptr) {
307
4.59k
        if (trc->isCallbackTracer()) {
308
0
            trc_ = trc->asCallbackTracer();
309
0
            MOZ_ASSERT(trc_->contextIndex_ == CallbackTracer::InvalidIndex);
310
0
            trc_->contextIndex_ = initial;
311
0
        }
312
4.59k
    }
313
4.59k
    ~AutoTracingIndex() {
314
4.59k
        if (trc_) {
315
0
            MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex);
316
0
            trc_->contextIndex_ = CallbackTracer::InvalidIndex;
317
0
        }
318
4.59k
    }
319
320
9.62k
    void operator++() {
321
9.62k
        if (trc_) {
322
0
            MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex);
323
0
            ++trc_->contextIndex_;
324
0
        }
325
9.62k
    }
326
};
327
328
// Set a context callback for the trace callback to use, if it needs a detailed
329
// edge description.
330
class MOZ_RAII AutoTracingDetails
331
{
332
    CallbackTracer* trc_;
333
334
  public:
335
0
    AutoTracingDetails(JSTracer* trc, CallbackTracer::ContextFunctor& func) : trc_(nullptr) {
336
0
        if (trc->isCallbackTracer()) {
337
0
            trc_ = trc->asCallbackTracer();
338
0
            MOZ_ASSERT(trc_->contextFunctor_ == nullptr);
339
0
            trc_->contextFunctor_ = &func;
340
0
        }
341
0
    }
Unexecuted instantiation: JS::AutoTracingDetails::AutoTracingDetails(JSTracer*, JS::CallbackTracer::ContextFunctor&)
Unexecuted instantiation: JS::AutoTracingDetails::AutoTracingDetails(JSTracer*, JS::CallbackTracer::ContextFunctor&)
342
0
    ~AutoTracingDetails() {
343
0
        if (trc_) {
344
0
            MOZ_ASSERT(trc_->contextFunctor_);
345
0
            trc_->contextFunctor_ = nullptr;
346
0
        }
347
0
    }
Unexecuted instantiation: JS::AutoTracingDetails::~AutoTracingDetails()
Unexecuted instantiation: JS::AutoTracingDetails::~AutoTracingDetails()
348
};
349
350
} // namespace JS
351
352
JS::CallbackTracer*
353
JSTracer::asCallbackTracer()
354
126
{
355
126
    MOZ_ASSERT(isCallbackTracer());
356
126
    return static_cast<JS::CallbackTracer*>(this);
357
126
}
358
359
namespace js {
360
namespace gc {
361
template <typename T>
362
JS_PUBLIC_API(void) TraceExternalEdge(JSTracer* trc, T* thingp, const char* name);
363
} // namespace gc
364
} // namespace js
365
366
namespace JS {
367
368
// The JS::TraceEdge family of functions traces the given GC thing reference.
369
// This performs the tracing action configured on the given JSTracer: typically
370
// calling the JSTracer::callback or marking the thing as live.
371
//
372
// The argument to JS::TraceEdge is an in-out param: when the function returns,
373
// the garbage collector might have moved the GC thing. In this case, the
374
// reference passed to JS::TraceEdge will be updated to the thing's new
375
// location. Callers of this method are responsible for updating any state that
376
// is dependent on the object's address. For example, if the object's address
377
// is used as a key in a hashtable, then the object must be removed and
378
// re-inserted with the correct hash.
379
//
380
// Note that while |edgep| must never be null, it is fine for |*edgep| to be
381
// nullptr.
382
383
template <typename T>
384
inline void
385
TraceEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name)
386
2.53k
{
387
2.53k
    MOZ_ASSERT(thingp);
388
2.53k
    if (*thingp) {
389
919
        js::gc::TraceExternalEdge(trc, thingp->unsafeGet(), name);
390
919
    }
391
2.53k
}
Unexecuted instantiation: void JS::TraceEdge<JS::Value>(JSTracer*, JS::Heap<JS::Value>*, char const*)
Unexecuted instantiation: void JS::TraceEdge<jsid>(JSTracer*, JS::Heap<jsid>*, char const*)
void JS::TraceEdge<JSObject*>(JSTracer*, JS::Heap<JSObject*>*, char const*)
Line
Count
Source
386
2.44k
{
387
2.44k
    MOZ_ASSERT(thingp);
388
2.44k
    if (*thingp) {
389
829
        js::gc::TraceExternalEdge(trc, thingp->unsafeGet(), name);
390
829
    }
391
2.44k
}
Unexecuted instantiation: void JS::TraceEdge<JSString*>(JSTracer*, JS::Heap<JSString*>*, char const*)
void JS::TraceEdge<JSScript*>(JSTracer*, JS::Heap<JSScript*>*, char const*)
Line
Count
Source
386
90
{
387
90
    MOZ_ASSERT(thingp);
388
90
    if (*thingp) {
389
90
        js::gc::TraceExternalEdge(trc, thingp->unsafeGet(), name);
390
90
    }
391
90
}
Unexecuted instantiation: void JS::TraceEdge<JSFunction*>(JSTracer*, JS::Heap<JSFunction*>*, char const*)
392
393
template <typename T>
394
inline void
395
TraceEdge(JSTracer* trc, JS::TenuredHeap<T>* thingp, const char* name)
396
2
{
397
2
    MOZ_ASSERT(thingp);
398
2
    if (T ptr = thingp->unbarrieredGetPtr()) {
399
0
        js::gc::TraceExternalEdge(trc, &ptr, name);
400
0
        thingp->setPtr(ptr);
401
0
    }
402
2
}
403
404
// Edges that are always traced as part of root marking do not require
405
// incremental barriers. This function allows for marking non-barriered
406
// pointers, but asserts that this happens during root marking.
407
//
408
// Note that while |edgep| must never be null, it is fine for |*edgep| to be
409
// nullptr.
410
template <typename T>
411
extern JS_PUBLIC_API(void)
412
UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name);
413
414
extern JS_PUBLIC_API(void)
415
TraceChildren(JSTracer* trc, GCCellPtr thing);
416
417
using ZoneSet = js::HashSet<Zone*, js::DefaultHasher<Zone*>, js::SystemAllocPolicy>;
418
using CompartmentSet = js::HashSet<JS::Compartment*, js::DefaultHasher<JS::Compartment*>,
419
                                   js::SystemAllocPolicy>;
420
421
/**
422
 * Trace every value within |compartments| that is wrapped by a
423
 * cross-compartment wrapper from a compartment that is not an element of
424
 * |compartments|.
425
 */
426
extern JS_PUBLIC_API(void)
427
TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments);
428
429
} // namespace JS
430
431
extern JS_PUBLIC_API(void)
432
JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
433
                     void* thing, JS::TraceKind kind, bool includeDetails);
434
435
namespace js {
436
437
// Trace an edge that is not a GC root and is not wrapped in a barriered
438
// wrapper for some reason.
439
//
440
// This method does not check if |*edgep| is non-null before tracing through
441
// it, so callers must check any nullable pointer before calling this method.
442
template <typename T>
443
extern JS_PUBLIC_API(void)
444
UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name);
445
446
namespace gc {
447
448
// Return true if the given edge is not live and is about to be swept.
449
template <typename T>
450
extern JS_PUBLIC_API(bool)
451
EdgeNeedsSweep(JS::Heap<T>* edgep);
452
453
// Not part of the public API, but declared here so we can use it in GCPolicy
454
// which is.
455
template <typename T>
456
bool
457
IsAboutToBeFinalizedUnbarriered(T* thingp);
458
459
} // namespace gc
460
} // namespace js
461
462
#endif /* js_TracingAPI_h */