michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef js_TracingAPI_h michael@0: #define js_TracingAPI_h michael@0: michael@0: #include "mozilla/NullPtr.h" michael@0: michael@0: #include "jspubtd.h" michael@0: michael@0: class JS_PUBLIC_API(JSTracer); michael@0: michael@0: namespace JS { michael@0: template class Heap; michael@0: template class TenuredHeap; michael@0: } michael@0: michael@0: // Tracer callback, called for each traceable thing directly referenced by a michael@0: // particular object or runtime structure. It is the callback responsibility michael@0: // to ensure the traversal of the full object graph via calling eventually michael@0: // JS_TraceChildren on the passed thing. In this case the callback must be michael@0: // prepared to deal with cycles in the traversal graph. michael@0: // michael@0: // kind argument is one of JSTRACE_OBJECT, JSTRACE_STRING or a tag denoting michael@0: // internal implementation-specific traversal kind. In the latter case the only michael@0: // operations on thing that the callback can do is to call JS_TraceChildren or michael@0: // JS_GetTraceThingInfo. michael@0: // michael@0: // If eagerlyTraceWeakMaps is true, when we trace a WeakMap visit all michael@0: // of its mappings. This should be used in cases where the tracer michael@0: // wants to use the existing liveness of entries. michael@0: typedef void michael@0: (* JSTraceCallback)(JSTracer *trc, void **thingp, JSGCTraceKind kind); michael@0: michael@0: // Callback that JSTraceOp implementation can provide to return a string michael@0: // describing the reference traced with JS_CallTracer. michael@0: typedef void michael@0: (* JSTraceNamePrinter)(JSTracer *trc, char *buf, size_t bufsize); michael@0: michael@0: enum WeakMapTraceKind { michael@0: DoNotTraceWeakMaps = 0, michael@0: TraceWeakMapValues = 1, michael@0: TraceWeakMapKeysValues = 2 michael@0: }; michael@0: michael@0: class JS_PUBLIC_API(JSTracer) michael@0: { michael@0: public: michael@0: JSTracer(JSRuntime *rt, JSTraceCallback traceCallback, michael@0: WeakMapTraceKind weakTraceKind = TraceWeakMapValues); michael@0: michael@0: // Set debugging information about a reference to a traceable thing to prepare michael@0: // for the following call to JS_CallTracer. michael@0: // michael@0: // When printer is null, arg must be const char * or char * C string naming michael@0: // the reference and index must be either (size_t)-1 indicating that the name michael@0: // alone describes the reference or it must be an index into some array vector michael@0: // that stores the reference. michael@0: // michael@0: // When printer callback is not null, the arg and index arguments are michael@0: // available to the callback as debugPrintArg_ and debugPrintIndex_ fields michael@0: // of JSTracer. michael@0: // michael@0: // The storage for name or callback's arguments needs to live only until michael@0: // the following call to JS_CallTracer returns. michael@0: void setTracingDetails(JSTraceNamePrinter printer, const void *arg, size_t index) { michael@0: debugPrinter_ = printer; michael@0: debugPrintArg_ = arg; michael@0: debugPrintIndex_ = index; michael@0: } michael@0: michael@0: void setTracingIndex(const char *name, size_t index) { michael@0: setTracingDetails(nullptr, (void *)name, index); michael@0: } michael@0: michael@0: void setTracingName(const char *name) { michael@0: setTracingDetails(nullptr, (void *)name, size_t(-1)); michael@0: } michael@0: michael@0: // Remove the currently set tracing details. michael@0: void clearTracingDetails() { michael@0: debugPrinter_ = nullptr; michael@0: debugPrintArg_ = nullptr; michael@0: } michael@0: michael@0: // Return true if tracing details are currently set. michael@0: bool hasTracingDetails() const; michael@0: michael@0: // Get the string set with the most recent call to setTracingName or return michael@0: // fallback if a name printer function has been installed. michael@0: const char *tracingName(const char *fallback) const; michael@0: michael@0: // Build a description of this edge in the heap graph. This call may invoke michael@0: // the debug printer, which may inspect arbitrary areas of the heap. michael@0: const char *getTracingEdgeName(char *buffer, size_t bufferSize); michael@0: michael@0: // Access the currently active tracing details. michael@0: JSTraceNamePrinter debugPrinter() const; michael@0: const void *debugPrintArg() const; michael@0: size_t debugPrintIndex() const; michael@0: michael@0: // Return the runtime set on the tracer. michael@0: JSRuntime *runtime() const { return runtime_; } michael@0: michael@0: // Return the weak map tracing behavior set on this tracer. michael@0: WeakMapTraceKind eagerlyTraceWeakMaps() const { return eagerlyTraceWeakMaps_; } michael@0: michael@0: // Update the trace callback. michael@0: void setTraceCallback(JSTraceCallback traceCallback); michael@0: michael@0: #ifdef JS_GC_ZEAL michael@0: // Sets the "real" location for a marked reference, when passing the address michael@0: // directly is not feasable. This address is used for matching against the michael@0: // store buffer when verifying the correctness of the entrees there. michael@0: // michael@0: // This is currently complicated by our need to nest calls for Values michael@0: // stored as keys in hash tables. michael@0: void setTracingLocation(void *location); michael@0: void unsetTracingLocation(); michael@0: void **tracingLocation(void **thingp); michael@0: #else michael@0: void setTracingLocation(void *location) {} michael@0: void unsetTracingLocation() {} michael@0: void **tracingLocation(void **thingp) { return nullptr; } michael@0: #endif michael@0: michael@0: // We expose |callback| directly so that IS_GC_MARKING_TRACER can compare michael@0: // it to GCMarker::GrayCallback. michael@0: JSTraceCallback callback; michael@0: michael@0: private: michael@0: JSRuntime *runtime_; michael@0: JSTraceNamePrinter debugPrinter_; michael@0: const void *debugPrintArg_; michael@0: size_t debugPrintIndex_; michael@0: WeakMapTraceKind eagerlyTraceWeakMaps_; michael@0: #ifdef JS_GC_ZEAL michael@0: void *realLocation_; michael@0: #endif michael@0: }; michael@0: michael@0: // The JS_Call*Tracer family of functions traces the given GC thing reference. michael@0: // This performs the tracing action configured on the given JSTracer: michael@0: // typically calling the JSTracer::callback or marking the thing as live. michael@0: // michael@0: // The argument to JS_Call*Tracer is an in-out param: when the function michael@0: // returns, the garbage collector might have moved the GC thing. In this case, michael@0: // the reference passed to JS_Call*Tracer will be updated to the object's new michael@0: // location. Callers of this method are responsible for updating any state michael@0: // that is dependent on the object's address. For example, if the object's michael@0: // address is used as a key in a hashtable, then the object must be removed michael@0: // and re-inserted with the correct hash. michael@0: // michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallValueTracer(JSTracer *trc, JS::Value *valuep, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallIdTracer(JSTracer *trc, jsid *idp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallObjectTracer(JSTracer *trc, JSObject **objp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallStringTracer(JSTracer *trc, JSString **strp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallScriptTracer(JSTracer *trc, JSScript **scriptp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallHeapValueTracer(JSTracer *trc, JS::Heap *valuep, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallHeapIdTracer(JSTracer *trc, JS::Heap *idp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallHeapObjectTracer(JSTracer *trc, JS::Heap *objp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallHeapStringTracer(JSTracer *trc, JS::Heap *strp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallHeapScriptTracer(JSTracer *trc, JS::Heap *scriptp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallHeapFunctionTracer(JSTracer *trc, JS::Heap *funp, const char *name); michael@0: michael@0: template michael@0: inline void michael@0: JS_CallHashSetObjectTracer(JSTracer *trc, HashSetEnum &e, JSObject *const &key, const char *name) michael@0: { michael@0: JSObject *updated = key; michael@0: trc->setTracingLocation(reinterpret_cast(&const_cast(key))); michael@0: JS_CallObjectTracer(trc, &updated, name); michael@0: if (updated != key) michael@0: e.rekeyFront(key, updated); michael@0: } michael@0: michael@0: // Trace an object that is known to always be tenured. No post barriers are michael@0: // required in this case. michael@0: extern JS_PUBLIC_API(void) michael@0: JS_CallTenuredObjectTracer(JSTracer *trc, JS::TenuredHeap *objp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_TraceRuntime(JSTracer *trc); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, michael@0: void *thing, JSGCTraceKind kind, bool includeDetails); michael@0: michael@0: #endif /* js_TracingAPI_h */