DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (4a108e94d3e2)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef js_TracingAPI_h
#define js_TracingAPI_h

#include "jsalloc.h"
#include "jspubtd.h"

#include "js/HashTable.h"

class JS_PUBLIC_API(JSTracer);

namespace JS {
template <typename T> class Heap;
template <typename T> class TenuredHeap;
}

// When tracing a thing, the GC needs to know about the layout of the object it
// is looking at. There are a fixed number of different layouts that the GC
// knows about. The "trace kind" is a static map which tells which layout a GC
// thing has.
//
// Although this map is public, the details are completely hidden. Not all of
// the matching C++ types are exposed, and those that are, are opaque.
//
// See Value::gcKind() and JSTraceCallback in Tracer.h for more details.
enum JSGCTraceKind
{
    // These trace kinds have a publicly exposed, although opaque, C++ type.
    // Note: The order here is determined by our Value packing. Other users
    //       should sort alphabetically, for consistency.
    JSTRACE_OBJECT = 0x00,
    JSTRACE_STRING = 0x01,
    JSTRACE_SYMBOL = 0x02,
    JSTRACE_SCRIPT = 0x03,

    // Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
    JSTRACE_SHAPE = 0x04,

    // The kind associated with a nullptr.
    JSTRACE_NULL = 0x06,

    // A kind that indicates the real kind should be looked up in the arena.
    JSTRACE_OUTOFLINE = 0x07,

    // The following kinds do not have an exposed C++ idiom.
    JSTRACE_BASE_SHAPE = 0x0F,
    JSTRACE_JITCODE = 0x1F,
    JSTRACE_LAZY_SCRIPT = 0x2F,
    JSTRACE_OBJECT_GROUP = 0x3F,

    JSTRACE_LAST = JSTRACE_OBJECT_GROUP
};

namespace JS {
// Returns a static string equivalent of |kind|.
JS_FRIEND_API(const char*)
GCTraceKindToAscii(JSGCTraceKind kind);
}

// Tracer callback, called for each traceable thing directly referenced by a
// particular object or runtime structure. It is the callback responsibility
// to ensure the traversal of the full object graph via calling eventually
// JS_TraceChildren on the passed thing. In this case the callback must be
// prepared to deal with cycles in the traversal graph.
//
// kind argument is one of JSTRACE_OBJECT, JSTRACE_STRING or a tag denoting
// internal implementation-specific traversal kind. In the latter case the only
// operations on thing that the callback can do is to call JS_TraceChildren or
// JS_GetTraceThingInfo.
//
// If eagerlyTraceWeakMaps is true, when we trace a WeakMap visit all
// of its mappings. This should be used in cases where the tracer
// wants to use the existing liveness of entries.
typedef void
(* JSTraceCallback)(JSTracer* trc, void** thingp, JSGCTraceKind kind);

// Callback that JSTraceOp implementation can provide to return a string
// describing the reference traced with JS_CallTracer.
typedef void
(* JSTraceNamePrinter)(JSTracer* trc, char* buf, size_t bufsize);

enum WeakMapTraceKind {
    DoNotTraceWeakMaps = 0,
    TraceWeakMapValues = 1,
    TraceWeakMapKeysValues = 2
};

class JS_PUBLIC_API(JSTracer)
{
  public:
    JSTracer(JSRuntime* rt, JSTraceCallback traceCallback,
             WeakMapTraceKind weakTraceKind = TraceWeakMapValues);

    // Set debugging information about a reference to a traceable thing to prepare
    // for the following call to JS_CallTracer.
    //
    // When printer is null, arg must be const char * or char * C string naming
    // the reference and index must be either (size_t)-1 indicating that the name
    // alone describes the reference or it must be an index into some array vector
    // that stores the reference.
    //
    // When printer callback is not null, the arg and index arguments are
    // available to the callback as debugPrintArg_ and debugPrintIndex_ fields
    // of JSTracer.
    //
    // The storage for name or callback's arguments needs to live only until
    // the following call to JS_CallTracer returns.
    void setTracingDetails(JSTraceNamePrinter printer, const void* arg, size_t index) {
        debugPrinter_ = printer;
        debugPrintArg_ = arg;
        debugPrintIndex_ = index;
    }

    void setTracingIndex(const char* name, size_t index) {
        setTracingDetails(nullptr, (void*)name, index);
    }

    void setTracingName(const char* name) {
        setTracingDetails(nullptr, (void*)name, size_t(-1));
    }

    // Remove the currently set tracing details.
    void clearTracingDetails() {
        debugPrinter_ = nullptr;
        debugPrintArg_ = nullptr;
    }

    // Return true if tracing details are currently set.
    bool hasTracingDetails() const;

    // Get the string set with the most recent call to setTracingName or return
    // fallback if a name printer function has been installed.
    const char* tracingName(const char* fallback) const;

    // Build a description of this edge in the heap graph. This call may invoke
    // the debug printer, which may inspect arbitrary areas of the heap.
    const char* getTracingEdgeName(char* buffer, size_t bufferSize);

    // Access the currently active tracing details.
    JSTraceNamePrinter debugPrinter() const;
    const void* debugPrintArg() const;
    size_t debugPrintIndex() const;

    // Return the runtime set on the tracer.
    JSRuntime* runtime() const { return runtime_; }

    // Return the weak map tracing behavior set on this tracer.
    WeakMapTraceKind eagerlyTraceWeakMaps() const { return eagerlyTraceWeakMaps_; }

    // Update the trace callback.
    void setTraceCallback(JSTraceCallback traceCallback);

#ifdef JS_GC_ZEAL
    // Sets the "real" location for a marked reference, when passing the address
    // directly is not feasable. This address is used for matching against the
    // store buffer when verifying the correctness of the entrees there.
    //
    // This is currently complicated by our need to nest calls for Values
    // stored as keys in hash tables.
    void setTracingLocation(void* location);
    void unsetTracingLocation();
    void** tracingLocation(void** thingp);
#else
    void setTracingLocation(void* location) {}
    void unsetTracingLocation() {}
    void** tracingLocation(void** thingp) { return nullptr; }
#endif

    // We expose |callback| directly so that IS_GC_MARKING_TRACER can compare
    // it to GCMarker::GrayCallback.
    JSTraceCallback     callback;

  private:
    JSRuntime*          runtime_;
    JSTraceNamePrinter  debugPrinter_;
    const void*         debugPrintArg_;
    size_t              debugPrintIndex_;
    WeakMapTraceKind    eagerlyTraceWeakMaps_;
#ifdef JS_GC_ZEAL
    void*               realLocation_;
#endif
};

// The JS_Call*Tracer family of functions traces the given GC thing reference.
// This performs the tracing action configured on the given JSTracer:
// typically calling the JSTracer::callback or marking the thing as live.
//
// The argument to JS_Call*Tracer is an in-out param: when the function
// returns, the garbage collector might have moved the GC thing. In this case,
// the reference passed to JS_Call*Tracer will be updated to the object's new
// location. Callers of this method are responsible for updating any state
// that is dependent on the object's address. For example, if the object's
// address is used as a key in a hashtable, then the object must be removed
// and re-inserted with the correct hash.
//
extern JS_PUBLIC_API(void)
JS_CallValueTracer(JSTracer* trc, JS::Heap<JS::Value>* valuep, const char* name);

extern JS_PUBLIC_API(void)
JS_CallIdTracer(JSTracer* trc, JS::Heap<jsid>* idp, const char* name);

extern JS_PUBLIC_API(void)
JS_CallObjectTracer(JSTracer* trc, JS::Heap<JSObject*>* objp, const char* name);

extern JS_PUBLIC_API(void)
JS_CallStringTracer(JSTracer* trc, JS::Heap<JSString*>* strp, const char* name);

extern JS_PUBLIC_API(void)
JS_CallScriptTracer(JSTracer* trc, JS::Heap<JSScript*>* scriptp, const char* name);

extern JS_PUBLIC_API(void)
JS_CallFunctionTracer(JSTracer* trc, JS::Heap<JSFunction*>* funp, const char* name);

// The following JS_CallUnbarriered*Tracer functions should only be called where
// you know for sure that a heap post barrier is not required.  Use with extreme
// caution!
extern JS_PUBLIC_API(void)
JS_CallUnbarrieredValueTracer(JSTracer* trc, JS::Value* valuep, const char* name);

extern JS_PUBLIC_API(void)
JS_CallUnbarrieredIdTracer(JSTracer* trc, jsid* idp, const char* name);

extern JS_PUBLIC_API(void)
JS_CallUnbarrieredObjectTracer(JSTracer* trc, JSObject** objp, const char* name);

extern JS_PUBLIC_API(void)
JS_CallUnbarrieredStringTracer(JSTracer* trc, JSString** strp, const char* name);

extern JS_PUBLIC_API(void)
JS_CallUnbarrieredScriptTracer(JSTracer* trc, JSScript** scriptp, const char* name);

template <typename HashSetEnum>
inline void
JS_CallHashSetObjectTracer(JSTracer* trc, HashSetEnum& e, JSObject* const& key, const char* name)
{
    JSObject* updated = key;
    trc->setTracingLocation(reinterpret_cast<void*>(&const_cast<JSObject*&>(key)));
    JS_CallUnbarrieredObjectTracer(trc, &updated, name);
    if (updated != key)
        e.rekeyFront(updated);
}

// Trace an object that is known to always be tenured.  No post barriers are
// required in this case.
extern JS_PUBLIC_API(void)
JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap<JSObject*>* objp, const char* name);

extern JS_PUBLIC_API(void)
JS_TraceChildren(JSTracer* trc, void* thing, JSGCTraceKind kind);

extern JS_PUBLIC_API(void)
JS_TraceRuntime(JSTracer* trc);

namespace JS {
typedef js::HashSet<Zone*, js::DefaultHasher<Zone*>, js::SystemAllocPolicy> ZoneSet;
}

// Trace every value within |zones| that is wrapped by a cross-compartment
// wrapper from a zone that is not an element of |zones|.
extern JS_PUBLIC_API(void)
JS_TraceIncomingCCWs(JSTracer* trc, const JS::ZoneSet& zones);

extern JS_PUBLIC_API(void)
JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
                     void* thing, JSGCTraceKind kind, bool includeDetails);

#endif /* js_TracingAPI_h */