Bug 375270: API to trace GC things graph without running the GC. r=brendan

This commit is contained in:
igor@mir2.org 2007-04-16 23:53:37 -07:00
parent 16b33e3aba
commit 904650319a
26 changed files with 1498 additions and 995 deletions

View File

@ -735,25 +735,8 @@ GC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
rt = cx->runtime;
preBytes = rt->gcBytes;
#ifdef GC_MARK_DEBUG
if (argc && JSVAL_IS_STRING(argv[0])) {
char *name = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
FILE *file = fopen(name, "w");
if (!file) {
fprintf(gErrFile, "gc: can't open %s: %s\n", strerror(errno));
return JS_FALSE;
}
js_DumpGCHeap = file;
} else {
js_DumpGCHeap = stdout;
}
#endif
JS_GC(cx);
#ifdef GC_MARK_DEBUG
if (js_DumpGCHeap != stdout)
fclose(js_DumpGCHeap);
js_DumpGCHeap = NULL;
#endif
fprintf(gOutFile, "before %lu, after %lu, break %08lx\n",
(unsigned long)preBytes, (unsigned long)rt->gcBytes,
#ifdef XP_UNIX
@ -1366,6 +1349,79 @@ DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_TRUE;
}
static JSBool
DumpHeap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
jsval v = JSVAL_NULL;
char *fileName = NULL;
size_t maxRecursionLevel = (size_t)-1;
void *thingToIgnore = NULL;
FILE *dumpFile;
JSBool ok;
JSTracer *trc;
if (argc != 0 && argv[0] != JSVAL_NULL && argv[0] != JSVAL_VOID) {
v = argv[0];
if (!JSVAL_IS_TRACEABLE(v)) {
fprintf(gErrFile,
"dumpHeap: the first argument is not null or "
"a heap-allocated thing\n");
return JS_FALSE;
}
}
if (argc > 1 && argv[1] != JSVAL_NULL && argv[1] != JSVAL_VOID) {
JSString *str;
str = JS_ValueToString(cx, argv[1]);
if (!str)
return JS_FALSE;
argv[1] = STRING_TO_JSVAL(str);
fileName = JS_GetStringBytes(str);
}
if (argc > 2 && argv[2] != JSVAL_NULL && argv[2] != JSVAL_VOID) {
uint32 depth;
if (!JS_ValueToECMAUint32(cx, argv[2], &depth))
return JS_FALSE;
maxRecursionLevel = depth;
}
if (argc > 3 && argv[3] != JSVAL_NULL && argv[3] != JSVAL_VOID) {
if (JSVAL_IS_GCTHING(argv[3]))
thingToIgnore = JSVAL_TO_GCTHING(argv[3]);
}
if (!fileName) {
dumpFile = stdout;
} else {
dumpFile = fopen(fileName, "w");
if (!dumpFile) {
fprintf(gErrFile, "gc: can't open %s: %s\n", strerror(errno));
return JS_FALSE;
}
}
trc = js_NewGCHeapDumper(cx, NULL, dumpFile, maxRecursionLevel,
thingToIgnore);
if (!trc) {
ok = JS_FALSE;
} else {
if (v == JSVAL_NULL) {
js_TraceRuntime(trc);
} else {
JS_TraceChildren(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
}
ok = js_FreeGCHeapDumper(trc);
}
if (dumpFile != stdout)
fclose(dumpFile);
return ok;
}
#endif /* DEBUG */
#ifdef TEST_EXPORT
@ -2146,6 +2202,7 @@ static JSFunctionSpec shell_functions[] = {
#ifdef DEBUG
{"dis", Disassemble, 1,0,0},
{"dissrc", DisassWithSrc, 1,0,0},
{"dumpHeap", DumpHeap, 3,0,0},
{"notes", Notes, 1,0,0},
{"tracing", Tracing, 0,0,0},
{"stats", DumpStats, 1,0,0},

View File

@ -1866,12 +1866,41 @@ JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
JS_PUBLIC_API(void)
JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
{
JS_ASSERT(cx->runtime->gcLevel > 0);
#ifdef JS_THREADSAFE
JS_ASSERT(cx->runtime->gcThread->id == js_CurrentThreadId());
#endif
JSTracer *trc;
GC_MARK(cx, thing, name);
trc = (JSTracer *)arg;
if (!trc)
trc = cx->runtime->gcMarkingTracer;
else
JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
#ifdef JS_THREADSAFE
JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
#endif
if (thing) {
JS_SET_TRACING_NAME(trc, name ? name : "unknown");
js_CallGCThingTracer(trc, thing);
}
}
extern JS_PUBLIC_API(JSBool)
JS_IsGCMarkingTracer(JSTracer *trc)
{
return IS_GC_MARKING_TRACER(trc);
}
JS_PUBLIC_API(JSTracer *)
JS_GetGCMarkingTracer(JSContext *cx)
{
JSRuntime *rt;
rt = cx->runtime;
JS_ASSERT(rt->gcMarkingTracer);
JS_ASSERT(rt->gcLevel > 0);
#ifdef JS_THREADSAFE
JS_ASSERT(rt->gcThread == rt->gcMarkingTracer->context->thread);
#endif
return rt->gcMarkingTracer;
}
JS_PUBLIC_API(void)
@ -3328,8 +3357,8 @@ prop_iter_finalize(JSContext *cx, JSObject *obj)
}
}
static uint32
prop_iter_mark(JSContext *cx, JSObject *obj, void *arg)
static void
prop_iter_trace(JSTracer *trc, JSObject *obj)
{
jsval v;
jsint i, n;
@ -3337,33 +3366,33 @@ prop_iter_mark(JSContext *cx, JSObject *obj, void *arg)
JSIdArray *ida;
jsid id;
v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
v = GC_AWARE_GET_SLOT(trc->context, obj, JSSLOT_PRIVATE);
JS_ASSERT(!JSVAL_IS_VOID(v));
i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX));
i = JSVAL_TO_INT(OBJ_GET_SLOT(trc->context, obj, JSSLOT_ITER_INDEX));
if (i < 0) {
/* Native case: just mark the next property to visit. */
sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v);
if (sprop)
MARK_SCOPE_PROPERTY(cx, sprop);
TRACE_SCOPE_PROPERTY(trc, sprop);
} else {
/* Non-native case: mark each id in the JSIdArray private. */
ida = (JSIdArray *) JSVAL_TO_PRIVATE(v);
for (i = 0, n = ida->length; i < n; i++) {
id = ida->vector[i];
MARK_ID(cx, id);
TRACE_ID(trc, id);
}
}
return 0;
}
static JSClass prop_iter_class = {
"PropertyIterator",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
JSCLASS_MARK_IS_TRACE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iter_finalize,
NULL, NULL, NULL, NULL,
NULL, NULL, prop_iter_mark, NULL
NULL, NULL, JS_CLASS_TRACE(prop_iter_trace), NULL
};
JS_PUBLIC_API(JSObject *)

View File

@ -45,6 +45,7 @@
#include <stddef.h>
#include <stdio.h>
#include "jspubtd.h"
#include "jsutil.h"
JS_BEGIN_EXTERN_C
@ -855,21 +856,168 @@ extern JS_PUBLIC_API(JSBool)
JS_UnlockGCThingRT(JSRuntime *rt, void *thing);
/*
* For implementors of JSObjectOps.mark, to mark a GC-thing reachable via a
* property or other strong ref identified for debugging purposes by name.
* The name argument's storage needs to live only as long as the call to
* this routine.
*
* The final arg is used by GC_MARK_DEBUG code to build a ref path through
* the GC's live thing graph. Implementors of JSObjectOps.mark should pass
* its final arg through to this function when marking all GC-things that are
* directly reachable from the object being marked.
*
* See the JSMarkOp typedef in jspubtd.h, and the JSObjectOps struct below.
* For implementors of JSMarkOp. All new code should implement JSTraceOp
* instead.
*/
extern JS_PUBLIC_API(void)
JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg);
/*
* JS_CallTracer API and related macros for implementors of JSTraceOp, to
* enumerate all references to traceable things reachable via a property or
* other strong ref identified for debugging purposes by name or index or
* a naming callaback.
*
* By definition references to traceable things include non-null pointers
* to JSObject, JSString and jsdouble and corresponding jsvals.
*
* See the JSTraceOp typedef in jspubtd.h.
*/
/* Trace kinds to pass to JS_Tracing. */
#define JSTRACE_OBJECT 0
#define JSTRACE_DOUBLE 1
#define JSTRACE_STRING 2
/*
* Use the following macros to check if a particular jsval is a traceable
* thing and to extract the thing and its kind to pass to JS_CallTracer.
*/
#define JSVAL_IS_TRACEABLE(v) (JSVAL_IS_GCTHING(v) && !JSVAL_IS_NULL(v))
#define JSVAL_TO_TRACEABLE(v) (JSVAL_TO_GCTHING(v))
#define JSVAL_TRACE_KIND(v) (JSVAL_TAG(v) >> 1)
JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_OBJECT) == JSTRACE_OBJECT);
JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_DOUBLE) == JSTRACE_DOUBLE);
JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_STRING) == JSTRACE_STRING);
struct JSTracer {
JSContext *context;
JSTraceCallback callback;
#ifdef DEBUG
JSTraceNamePrinter debugPrinter;
const void *debugPrintArg;
size_t debugPrintIndex;
#endif
};
/*
* The method to call on each reference to a traceable thing storted in a
* particular JSObject or other runtime structure. With DEBUG defined the
* caller before calling JS_CallTracer must initialize JSTracer fields
* describing the reference using the macros bellow.
*/
extern JS_PUBLIC_API(void)
JS_CallTracer(JSTracer *trc, void *thing, uint32 kind);
/*
* 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 debugPrinterArg 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.
*/
#ifdef DEBUG
# define JS_SET_TRACING_DETAILS(trc, printer, arg, index) \
JS_BEGIN_MACRO \
(trc)->debugPrinter = (printer); \
(trc)->debugPrintArg = (arg); \
(trc)->debugPrintIndex = (index); \
JS_END_MACRO
#else
# define JS_SET_TRACING_DETAILS(trc, printer, arg, index) \
JS_BEGIN_MACRO \
JS_END_MACRO
#endif
/*
* Convenience macro to describe the argument of JS_CallTracer using C string
* and index.
*/
# define JS_SET_TRACING_INDEX(trc, name, index) \
JS_SET_TRACING_DETAILS(trc, NULL, name, index)
/*
* Convenience macro to describe the argument of JS_CallTracer using C string.
*/
# define JS_SET_TRACING_NAME(trc, name) \
JS_SET_TRACING_DETAILS(trc, NULL, name, (size_t)-1)
/*
* Convenience macro to invoke JS_CallTracer using C string as the name for
* the reference to a traceable thing.
*/
# define JS_CALL_TRACER(trc, thing, kind, name) \
JS_BEGIN_MACRO \
JS_SET_TRACING_NAME(trc, name); \
JS_CallTracer((trc), (thing), (kind)); \
JS_END_MACRO
/*
* Convenience macros to invoke JS_CallTracer when jsval represents a
* reference to a traceable thing.
*/
#define JS_CALL_VALUE_TRACER(trc, val, name) \
JS_BEGIN_MACRO \
if (JSVAL_IS_TRACEABLE(val)) { \
JS_CALL_TRACER((trc), JSVAL_TO_GCTHING(val), \
JSVAL_TRACE_KIND(val), name); \
} \
JS_END_MACRO
#define JS_CALL_OBJECT_TRACER(trc, object, name) \
JS_BEGIN_MACRO \
JSObject *obj_ = (object); \
JS_ASSERT(object); \
JS_CALL_TRACER((trc), obj_, JSTRACE_OBJECT, name); \
JS_END_MACRO
#define JS_CALL_STRING_TRACER(trc, string, name) \
JS_BEGIN_MACRO \
JSString *str_ = (string); \
JS_ASSERT(string); \
JS_CALL_TRACER((trc), str_, JSTRACE_STRING, name); \
JS_END_MACRO
#define JS_CALL_DOUBLE_TRACER(trc, number, name) \
JS_BEGIN_MACRO \
jsdouble *num_ = (number); \
JS_ASSERT(number); \
JS_CALL_TRACER((trc), num_, JSTRACE_DOUBLE, name); \
JS_END_MACRO
/*
* API for JSTraceCallback implementations.
*/
# define JS_TRACER_INIT(trc, cx_, callback_) \
JS_BEGIN_MACRO \
(trc)->context = (cx_); \
(trc)->callback = (callback_); \
JS_SET_TRACING_DETAILS(trc, NULL, NULL, (size_t)-1); \
JS_END_MACRO
extern JS_PUBLIC_API(void)
JS_TraceChildren(JSTracer *trc, void *thing, uintN type);
#ifdef DEBUG
extern JS_PUBLIC_API(void)
JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
void *thing, uint32 kind, JSBool includeDetails);
#endif
/*
* Garbage collector API.
*/
extern JS_PUBLIC_API(void)
JS_GC(JSContext *cx);
@ -882,6 +1030,12 @@ JS_SetGCCallback(JSContext *cx, JSGCCallback cb);
extern JS_PUBLIC_API(JSGCCallback)
JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb);
extern JS_PUBLIC_API(JSBool)
JS_IsGCMarkingTracer(JSTracer *trc);
extern JS_PUBLIC_API(JSTracer *)
JS_GetGCMarkingTracer(JSContext *cx);
extern JS_PUBLIC_API(void)
JS_SetGCThingCallback(JSContext *cx, JSGCThingCallback cb, void *closure);
@ -1029,6 +1183,9 @@ struct JSExtendedClass {
#define JSCLASS_IS_ANONYMOUS (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1))
#define JSCLASS_IS_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2))
/* Idicates that JSClass.mark is a tracer with JSTraceOp type. */
#define JSCLASS_MARK_IS_TRACE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3))
/*
* ECMA-262 requires that most constructors used internally create objects
* with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
@ -1083,7 +1240,7 @@ struct JSObjectOps {
JSHasInstanceOp hasInstance;
JSSetObjectSlotOp setProto;
JSSetObjectSlotOp setParent;
JSMarkOp mark;
JSTraceOp trace;
JSFinalizeOp clear;
JSGetRequiredSlotOp getRequiredSlot;
JSSetRequiredSlotOp setRequiredSlot;

View File

@ -424,42 +424,53 @@ js_FinishAtomState(JSAtomState *state)
js_FreeAtomState(NULL, state);
}
typedef struct MarkArgs {
JSBool keepAtoms;
JSGCThingMarker mark;
void *data;
} MarkArgs;
JS_STATIC_DLL_CALLBACK(intN)
js_atom_marker(JSHashEntry *he, intN i, void *arg)
void
js_TraceAtom(JSTracer *trc, JSAtom *atom)
{
JSAtom *atom;
MarkArgs *args;
jsval key;
key = ATOM_KEY(atom);
JS_CALL_VALUE_TRACER(trc, key, "key");
if (atom->flags & ATOM_HIDDEN)
JS_CALL_TRACER(trc, atom->entry.value, JSTRACE_ATOM, "hidden");
}
typedef struct TraceArgs {
JSBool allAtoms;
JSTracer *trc;
} TraceArgs;
JS_STATIC_DLL_CALLBACK(intN)
js_locked_atom_tracer(JSHashEntry *he, intN i, void *arg)
{
JSAtom *atom;
TraceArgs *args;
atom = (JSAtom *)he;
args = (MarkArgs *)arg;
if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) || args->keepAtoms) {
atom->flags |= ATOM_MARK;
key = ATOM_KEY(atom);
if (JSVAL_IS_GCTHING(key))
args->mark(JSVAL_TO_GCTHING(key), args->data);
args = (TraceArgs *)arg;
if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) || args->allAtoms) {
JS_CALL_TRACER(args->trc, atom, JSTRACE_ATOM,
(atom->flags & ATOM_PINNED)
? "pinned_atom"
: (atom->flags & ATOM_INTERNED)
? "interned_atom"
: "locked_atom");
}
return HT_ENUMERATE_NEXT;
}
void
js_MarkAtomState(JSAtomState *state, JSBool keepAtoms, JSGCThingMarker mark,
void *data)
js_TraceLockedAtoms(JSTracer *trc, JSBool allAtoms)
{
MarkArgs args;
JSAtomState *state;
TraceArgs args;
state = &trc->context->runtime->atomState;
if (!state->table)
return;
args.keepAtoms = keepAtoms;
args.mark = mark;
args.data = data;
JS_HashTableEnumerateEntries(state->table, js_atom_marker, &args);
args.allAtoms = allAtoms;
args.trc = trc;
JS_HashTableEnumerateEntries(state->table, js_locked_atom_tracer, &args);
}
JS_STATIC_DLL_CALLBACK(intN)

View File

@ -345,14 +345,14 @@ extern void
js_FinishAtomState(JSAtomState *state);
/*
* Atom garbage collection hooks.
* Atom tracing and garbage collection hooks.
*/
typedef void
(*JSGCThingMarker)(void *thing, void *data);
extern void
js_MarkAtomState(JSAtomState *state, JSBool keepAtoms, JSGCThingMarker mark,
void *data);
js_TraceAtom(JSTracer *trc, JSAtom *atom);
extern void
js_TraceLockedAtoms(JSTracer *trc, JSBool allAtoms);
extern void
js_SweepAtomState(JSAtomState *state);

View File

@ -798,10 +798,11 @@ js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v)
}
void
js_MarkLocalRoots(JSContext *cx, JSLocalRootStack *lrs)
js_TraceLocalRoots(JSTracer *trc, JSLocalRootStack *lrs)
{
uint32 n, m, mark;
JSLocalRootChunk *lrc;
jsval v;
n = lrs->rootCount;
if (n == 0)
@ -811,13 +812,19 @@ js_MarkLocalRoots(JSContext *cx, JSLocalRootStack *lrs)
lrc = lrs->topChunk;
do {
while (--n > mark) {
#ifdef GC_MARK_DEBUG
char name[22];
JS_snprintf(name, sizeof name, "<local root %u>", n);
#endif
m = n & JSLRS_CHUNK_MASK;
JS_ASSERT(JSVAL_IS_GCTHING(lrc->roots[m]));
GC_MARK(cx, JSVAL_TO_GCTHING(lrc->roots[m]), name);
v = lrc->roots[m];
JS_ASSERT(JSVAL_IS_GCTHING(v) && v != JSVAL_NULL);
JS_SET_TRACING_INDEX(trc, "local_root", n);
/*
* When v is tagged as an object, it can be in fact an arbitrary
* GC thing so we have to use js_CallGCThingTracer on it.
*/
if (JSVAL_IS_OBJECT(v))
js_CallGCThingTracer(trc, JSVAL_TO_GCTHING(v));
else
JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
if (m == 0)
lrc = lrc->down;
}

View File

@ -186,6 +186,7 @@ struct JSRuntime {
uint32 gcMaxMallocBytes;
uint32 gcLevel;
uint32 gcNumber;
JSTracer *gcMarkingTracer;
/*
* NB: do not pack another flag here by claiming gcPadding unless the new
@ -382,7 +383,7 @@ struct JSRuntime {
/*
* A helper list for the GC, so it can mark native iterator states. See
* js_MarkNativeIteratorStates for details.
* js_TraceNativeIteratorStates for details.
*/
JSNativeIteratorState *nativeIteratorStates;
@ -508,14 +509,14 @@ typedef struct JSLocalRootStack {
typedef struct JSTempValueRooter JSTempValueRooter;
typedef void
(* JS_DLL_CALLBACK JSTempValueMarker)(JSContext *cx, JSTempValueRooter *tvr);
(* JS_DLL_CALLBACK JSTempValueTrace)(JSTracer *trc, JSTempValueRooter *tvr);
typedef union JSTempValueUnion {
jsval value;
JSObject *object;
JSString *string;
void *gcthing;
JSTempValueMarker marker;
JSTempValueTrace trace;
JSScopeProperty *sprop;
JSWeakRoots *weakRoots;
jsval *array;
@ -532,7 +533,7 @@ JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(JSObject *));
* Context-linked stack of temporary GC roots.
*
* If count is -1, then u.value contains the single value or GC-thing to root.
* If count is -2, then u.marker holds a mark hook called to mark the values.
* If count is -2, then u.trace holds a trace hook called to trace the values.
* If count is -3, then u.sprop points to the property tree node to mark.
* If count is -4, then u.weakRoots points to saved weak roots.
* If count >= 0, then u.array points to a stack-allocated vector of jsvals.
@ -565,7 +566,7 @@ struct JSTempValueRooter {
};
#define JSTVU_SINGLE (-1)
#define JSTVU_MARKER (-2)
#define JSTVU_TRACE (-2)
#define JSTVU_SPROP (-3)
#define JSTVU_WEAK_ROOTS (-4)
@ -591,10 +592,10 @@ struct JSTempValueRooter {
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
JS_END_MACRO
#define JS_PUSH_TEMP_ROOT_MARKER(cx,marker_,tvr) \
#define JS_PUSH_TEMP_ROOT_TRACE(cx,trace_,tvr) \
JS_BEGIN_MACRO \
(tvr)->count = JSTVU_MARKER; \
(tvr)->u.marker = (marker_); \
(tvr)->count = JSTVU_TRACE; \
(tvr)->u.trace = (trace_); \
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
JS_END_MACRO
@ -773,11 +774,6 @@ struct JSContext {
/* Stack of thread-stack-allocated temporary GC roots. */
JSTempValueRooter *tempValueRooters;
#ifdef GC_MARK_DEBUG
/* Top of the GC mark stack. */
void *gcCurrentMarkNode;
#endif
};
#ifdef JS_THREADSAFE
@ -935,7 +931,7 @@ extern int
js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v);
extern void
js_MarkLocalRoots(JSContext *cx, JSLocalRootStack *lrs);
js_TraceLocalRoots(JSTracer *trc, JSLocalRootStack *lrs);
/*
* Report an exception, which is currently realized as a printf-style format

View File

@ -392,23 +392,24 @@ DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag)
}
/*
* NB: js_MarkWatchPoints does not acquire cx->runtime->debuggerLock, since
* NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
* the debugger should never be racing with the GC (i.e., the debugger must
* respect the request model).
*/
void
js_MarkWatchPoints(JSContext *cx)
js_TraceWatchPoints(JSTracer *trc)
{
JSRuntime *rt;
JSWatchPoint *wp;
rt = cx->runtime;
rt = trc->context->runtime;
for (wp = (JSWatchPoint *)rt->watchPointList.next;
wp != (JSWatchPoint *)&rt->watchPointList;
wp = (JSWatchPoint *)wp->links.next) {
MARK_SCOPE_PROPERTY(cx, wp->sprop);
if (wp->sprop->attrs & JSPROP_SETTER)
JS_MarkGCThing(cx, wp->setter, "wp->setter", NULL);
TRACE_SCOPE_PROPERTY(trc, wp->sprop);
if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter)
JS_CALL_OBJECT_TRACER(trc, (JSObject *)wp->setter, "wp->setter");
}
}

View File

@ -99,7 +99,7 @@ JS_ClearAllWatchPoints(JSContext *cx);
* header file "jsconfig.h" has been included.
*/
extern void
js_MarkWatchPoints(JSContext *cx);
js_TraceWatchPoints(JSTracer *trc);
extern JSScopeProperty *
js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id);

View File

@ -67,8 +67,8 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
static void
exn_finalize(JSContext *cx, JSObject *obj);
static uint32
exn_mark(JSContext *cx, JSObject *obj, void *arg);
static void
exn_trace(JSTracer *trc, JSObject *obj);
static void
exn_finalize(JSContext *cx, JSObject *obj);
@ -82,12 +82,12 @@ exn_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSClass js_ErrorClass = {
js_Error_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_MARK_IS_TRACE |
JSCLASS_HAS_CACHED_PROTO(JSProto_Error),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
exn_enumerate, (JSResolveOp)exn_resolve, JS_ConvertStub, exn_finalize,
NULL, NULL, NULL, Exception,
NULL, NULL, exn_mark, NULL
NULL, NULL, JS_CLASS_TRACE(exn_trace), NULL
};
typedef struct JSStackTraceElem {
@ -375,34 +375,37 @@ GetExnPrivate(JSContext *cx, JSObject *obj)
return priv;
}
static uint32
exn_mark(JSContext *cx, JSObject *obj, void *arg)
static void
exn_trace(JSTracer *trc, JSObject *obj)
{
JSExnPrivate *priv;
JSStackTraceElem *elem;
size_t vcount, i;
jsval *vp, v;
priv = GetExnPrivate(cx, obj);
priv = GetExnPrivate(trc->context, obj);
if (priv) {
GC_MARK(cx, priv->message, "exception message");
GC_MARK(cx, priv->filename, "exception filename");
if (priv->message)
JS_CALL_STRING_TRACER(trc, priv->message, "exception message");
if (priv->filename)
JS_CALL_STRING_TRACER(trc, priv->filename, "exception filename");
elem = priv->stackElems;
for (vcount = i = 0; i != priv->stackDepth; ++i, ++elem) {
if (elem->funName)
GC_MARK(cx, elem->funName, "stack trace function name");
if (elem->filename)
if (elem->funName) {
JS_CALL_STRING_TRACER(trc, elem->funName,
"stack trace function name");
}
if (IS_GC_MARKING_TRACER(trc) && elem->filename)
js_MarkScriptFilename(elem->filename);
vcount += elem->argc;
}
vp = GetStackTraceValueBuffer(priv);
for (i = 0; i != vcount; ++i, ++vp) {
v = *vp;
if (JSVAL_IS_GCTHING(v))
GC_MARK(cx, JSVAL_TO_GCTHING(v), "stack trace argument");
JS_CALL_VALUE_TRACER(trc, v, "stack trace argument");
}
}
return 0;
}
static void

View File

@ -544,18 +544,19 @@ args_enumerate(JSContext *cx, JSObject *obj)
* If a generator-iterator's arguments or call object escapes, it needs to
* mark its generator object.
*/
static uint32
args_or_call_mark(JSContext *cx, JSObject *obj, void *arg)
static void
args_or_call_trace(JSTracer *trc, JSObject *obj)
{
JSStackFrame *fp;
fp = JS_GetPrivate(cx, obj);
if (fp && (fp->flags & JSFRAME_GENERATOR))
GC_MARK(cx, FRAME_TO_GENERATOR(fp)->obj, "FRAME_TO_GENERATOR(fp)->obj");
return 0;
fp = JS_GetPrivate(trc->context, obj);
if (fp && (fp->flags & JSFRAME_GENERATOR)) {
JS_CALL_OBJECT_TRACER(trc, FRAME_TO_GENERATOR(fp)->obj,
"FRAME_TO_GENERATOR(fp)->obj");
}
}
#else
# define args_or_call_mark NULL
# define args_or_call_trace NULL
#endif
/*
@ -572,7 +573,7 @@ args_or_call_mark(JSContext *cx, JSObject *obj, void *arg)
JSClass js_ArgumentsClass = {
js_Object_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
JS_PropertyStub, args_delProperty,
args_getProperty, args_setProperty,
args_enumerate, (JSResolveOp) args_resolve,
@ -580,7 +581,7 @@ JSClass js_ArgumentsClass = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
args_or_call_mark, NULL
JS_CLASS_TRACE(args_or_call_trace), NULL
};
JSObject *
@ -936,7 +937,7 @@ call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
JSClass js_CallClass = {
js_Call_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS |
JSCLASS_HAS_CACHED_PROTO(JSProto_Call),
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Call),
JS_PropertyStub, JS_PropertyStub,
call_getProperty, call_setProperty,
call_enumerate, (JSResolveOp)call_resolve,
@ -944,7 +945,7 @@ JSClass js_CallClass = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
args_or_call_mark, NULL,
JS_CLASS_TRACE(args_or_call_trace), NULL,
};
/*
@ -1438,20 +1439,19 @@ fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp);
}
static uint32
fun_mark(JSContext *cx, JSObject *obj, void *arg)
static void
fun_trace(JSTracer *trc, JSObject *obj)
{
JSFunction *fun;
fun = (JSFunction *) JS_GetPrivate(cx, obj);
fun = (JSFunction *) JS_GetPrivate(trc->context, obj);
if (fun) {
GC_MARK(cx, fun, "private");
JS_CALL_TRACER(trc, fun, JSTRACE_FUNCTION, "private");
if (fun->atom)
GC_MARK_ATOM(cx, fun->atom);
JS_CALL_TRACER(trc, fun->atom, JSTRACE_ATOM, "name");
if (FUN_INTERPRETED(fun) && fun->u.i.script)
js_MarkScript(cx, fun->u.i.script);
js_TraceScript(trc, fun->u.i.script);
}
return 0;
}
static uint32
@ -1471,7 +1471,7 @@ fun_reserveSlots(JSContext *cx, JSObject *obj)
JS_FRIEND_DATA(JSClass) js_FunctionClass = {
js_Function_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
JS_PropertyStub, JS_PropertyStub,
fun_getProperty, JS_PropertyStub,
fun_enumerate, (JSResolveOp)fun_resolve,
@ -1479,7 +1479,7 @@ JS_FRIEND_DATA(JSClass) js_FunctionClass = {
NULL, NULL,
NULL, NULL,
fun_xdrObject, fun_hasInstance,
fun_mark, fun_reserveSlots
JS_CLASS_TRACE(fun_trace), fun_reserveSlots
};
JSBool

File diff suppressed because it is too large Load Diff

View File

@ -201,40 +201,48 @@ js_UnlockGCThingRT(JSRuntime *rt, void *thing);
extern JSBool
js_IsAboutToBeFinalized(JSContext *cx, void *thing);
extern void
js_MarkAtom(JSContext *cx, JSAtom *atom);
#define GC_MARK_ATOM(cx, atom) \
JS_BEGIN_MACRO \
js_MarkAtom(cx, atom); \
JS_END_MACRO
/*
* Always use GC_MARK macro and never call js_MarkGCThing directly so
* when GC_MARK_DEBUG is defined the dump of live GC things does not miss
* a thing.
* Macro to test if a traversal is the marking phase of GC to avoid exposing
* JSAtom and ScriptFilenameEntry to traversal implementations.
*/
extern void
js_MarkGCThing(JSContext *cx, void *thing);
#define IS_GC_MARKING_TRACER(trc) ((trc)->callback == NULL)
#ifdef GC_MARK_DEBUG
#ifdef DEBUG
# define GC_MARK(cx, thing, name) js_MarkNamedGCThing(cx, thing, name)
extern JS_FRIEND_API(JSTracer *)
js_NewGCHeapDumper(JSContext *cx, void *thingToFind, FILE *fp,
size_t maxRecursionDepth, void *thingToIgnore);
extern void
js_MarkNamedGCThing(JSContext *cx, void *thing, const char *name);
extern JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
JS_EXTERN_DATA(void *) js_LiveThingToFind;
#else
# define GC_MARK(cx, thing, name) js_MarkGCThing(cx, thing)
extern JS_FRIEND_API(JSBool)
js_FreeGCHeapDumper(JSTracer *trc);
#endif
JS_STATIC_ASSERT(JSTRACE_STRING == 2);
#define JSTRACE_FUNCTION 3
#define JSTRACE_ATOM 4
#define JSTRACE_NAMESPACE 5
#define JSTRACE_QNAME 6
#define JSTRACE_XML 7
#if JS_HAS_XML_SUPPORT
# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_XML)
#else
# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_ATOM)
#endif
extern void
js_MarkStackFrame(JSContext *cx, JSStackFrame *fp);
js_CallGCThingTracer(JSTracer *trc, void *thing);
extern void
js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp);
extern JS_FRIEND_API(void)
js_TraceRuntime(JSTracer *trc);
extern JS_FRIEND_API(void)
js_TraceContext(JSTracer *trc, JSContext *acx);
/*
* Kinds of js_GC invocation.
@ -353,6 +361,7 @@ typedef struct JSWeakRoots {
JS_STATIC_ASSERT(JSVAL_NULL == 0);
#define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots)))
#ifdef DEBUG_notme
#define TOO_MUCH_GC 1
#endif

View File

@ -1435,7 +1435,7 @@ js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
* references to such results.
*/
*rval = POP_OPND();
if (JSVAL_IS_GCTHING(*rval)) {
if (JSVAL_IS_GCTHING(*rval) && *rval != JSVAL_NULL) {
if (cx->localRootStack) {
if (js_PushLocalRoot(cx, cx->localRootStack, *rval) < 0)
ok = JS_FALSE;

View File

@ -665,33 +665,33 @@ generator_finalize(JSContext *cx, JSObject *obj)
}
}
static uint32
generator_mark(JSContext *cx, JSObject *obj, void *arg)
static void
generator_trace(JSTracer *trc, JSObject *obj)
{
JSGenerator *gen;
gen = (JSGenerator *) JS_GetPrivate(cx, obj);
gen = (JSGenerator *) JS_GetPrivate(trc->context, obj);
if (gen) {
/*
* We must mark argv[-2], as js_MarkStackFrame will not. Note that
* js_MarkStackFrame will mark thisp (argv[-1]) and actual arguments,
* plus any missing formals and local GC roots.
* We must trace argv[-2], as js_TraceStackFrame will not. Note
* that js_TraceStackFrame will trace thisp (argv[-1]) and actual
* arguments, plus any missing formals and local GC roots.
*/
JS_ASSERT(!JSVAL_IS_PRIMITIVE(gen->frame.argv[-2]));
GC_MARK(cx, JSVAL_TO_GCTHING(gen->frame.argv[-2]), "generator");
js_MarkStackFrame(cx, &gen->frame);
JS_CALL_OBJECT_TRACER(trc, JSVAL_TO_OBJECT(gen->frame.argv[-2]),
"generator");
js_TraceStackFrame(trc, &gen->frame);
}
return 0;
}
JSClass js_GeneratorClass = {
js_Generator_str,
JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS |
JSCLASS_HAS_CACHED_PROTO(JSProto_Generator),
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, generator_finalize,
NULL, NULL, NULL, NULL,
NULL, NULL, generator_mark, NULL
NULL, NULL, JS_CLASS_TRACE(generator_trace), NULL
};
/*

View File

@ -103,7 +103,7 @@ JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
js_Call, js_Construct,
NULL, js_HasInstance,
js_SetProtoOrParent, js_SetProtoOrParent,
js_Mark, js_Clear,
js_TraceObject, js_Clear,
js_GetRequiredSlot, js_SetRequiredSlot
};
@ -663,12 +663,13 @@ js_LeaveSharpObject(JSContext *cx, JSIdArray **idap)
JS_STATIC_DLL_CALLBACK(intN)
gc_sharp_table_entry_marker(JSHashEntry *he, intN i, void *arg)
{
GC_MARK((JSContext *)arg, (JSObject *)he->key, "sharp table entry");
JS_CALL_OBJECT_TRACER((JSTracer *)arg, (JSObject *)he->key,
"sharp table entry");
return JS_DHASH_NEXT;
}
void
js_GCMarkSharpMap(JSContext *cx, JSSharpObjectMap *map)
js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map)
{
JS_ASSERT(map->depth > 0);
JS_ASSERT(map->table);
@ -693,7 +694,7 @@ js_GCMarkSharpMap(JSContext *cx, JSSharpObjectMap *map)
* with otherwise unreachable objects. But this is way too complex
* to justify spending efforts.
*/
JS_HashTableEnumerateEntries(map->table, gc_sharp_table_entry_marker, cx);
JS_HashTableEnumerateEntries(map->table, gc_sharp_table_entry_marker, trc);
}
#define OBJ_TOSTRING_EXTRA 4 /* for 4 local GC roots */
@ -1872,7 +1873,7 @@ JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
NULL, NULL,
NULL, NULL,
js_SetProtoOrParent, js_SetProtoOrParent,
js_Mark, js_Clear,
js_TraceObject, js_Clear,
NULL, NULL
};
@ -4108,12 +4109,12 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
}
void
js_MarkNativeIteratorStates(JSContext *cx)
js_TraceNativeIteratorStates(JSTracer *trc)
{
JSNativeIteratorState *state;
jsid *cursor, *end, id;
state = cx->runtime->nativeIteratorStates;
state = trc->context->runtime->nativeIteratorStates;
if (!state)
return;
@ -4123,7 +4124,7 @@ js_MarkNativeIteratorStates(JSContext *cx)
end = cursor + state->ida->length;
for (; cursor != end; ++cursor) {
id = *cursor;
MARK_ID(cx, id);
TRACE_ID(trc, id);
}
} while ((state = state->next) != NULL);
}
@ -4750,12 +4751,75 @@ js_DumpScopeMeters(JSRuntime *rt)
}
#endif
uint32
js_Mark(JSContext *cx, JSObject *obj, void *arg)
#ifdef DEBUG
static void
PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
{
JSObject *obj;
uint32 slot;
JSScope *scope;
jsval nval;
JSScopeProperty *sprop;
JSClass *clasp;
uint32 key;
const char *slotname;
JS_ASSERT(trc->debugPrinter == PrintObjectSlotName);
obj = (JSObject *)trc->debugPrintArg;
slot = (uint32)trc->debugPrintIndex;
scope = OBJ_SCOPE(obj);
sprop = SCOPE_LAST_PROP(scope);
while (sprop && sprop->slot != slot)
sprop = sprop->parent;
if (!sprop) {
switch (slot) {
case JSSLOT_PROTO:
JS_snprintf(buf, bufsize, "__proto__");
break;
case JSSLOT_PARENT:
JS_snprintf(buf, bufsize, "__parent__");
break;
default:
slotname = NULL;
clasp = LOCKED_OBJ_GET_CLASS(obj);
if (clasp->flags & JSCLASS_IS_GLOBAL) {
key = slot - JSSLOT_START(clasp);
#define JS_PROTO(name,code,init) \
if ((code) == key) { slotname = js_##name##_str; goto found; }
#include "jsproto.tbl"
#undef JS_PROTO
}
found:
if (slotname)
JS_snprintf(buf, bufsize, "CLASS_OBJECT(%s)", slotname);
else
JS_snprintf(buf, bufsize, "**UNKNOWN SLOT %ld**", (long)slot);
break;
}
} else {
nval = ID_TO_VALUE(sprop->id);
if (JSVAL_IS_INT(nval)) {
JS_snprintf(buf, bufsize, "%ld", (long)JSVAL_TO_INT(nval));
} else if (JSVAL_IS_STRING(nval)) {
js_PutEscapedString(buf, bufsize, JSVAL_TO_STRING(nval), 0);
} else {
JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
}
}
}
#endif
void
js_TraceObject(JSTracer *trc, JSObject *obj)
{
JSScope *scope;
JSContext *cx;
JSScopeProperty *sprop;
JSClass *clasp;
size_t nslots, i;
jsval v;
JS_ASSERT(OBJ_IS_NATIVE(obj));
scope = OBJ_SCOPE(obj);
@ -4767,16 +4831,21 @@ js_Mark(JSContext *cx, JSObject *obj, void *arg)
JS_ASSERT(!SCOPE_LAST_PROP(scope) ||
SCOPE_HAS_PROPERTY(scope, SCOPE_LAST_PROP(scope)));
cx = trc->context;
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
continue;
MARK_SCOPE_PROPERTY(cx, sprop);
TRACE_SCOPE_PROPERTY(trc, sprop);
}
/* No one runs while the GC is running, so we can use LOCKED_... here. */
clasp = LOCKED_OBJ_GET_CLASS(obj);
if (clasp->mark)
(void) clasp->mark(cx, obj, NULL);
if (clasp->mark) {
if (clasp->flags & JSCLASS_MARK_IS_TRACE)
((JSTraceOp)(clasp->mark))(trc, obj);
else if (IS_GC_MARKING_TRACER(trc))
(void) clasp->mark(cx, obj, trc);
}
if (scope->object != obj) {
/*
@ -4784,9 +4853,18 @@ js_Mark(JSContext *cx, JSObject *obj, void *arg)
* how many slots are in use in obj by looking at scope, so we use
* STOBJ_NSLOTS(obj).
*/
return STOBJ_NSLOTS(obj);
nslots = STOBJ_NSLOTS(obj);
} else {
nslots = LOCKED_OBJ_NSLOTS(obj);
}
for (i = 0; i != nslots; ++i) {
v = STOBJ_GET_SLOT(obj, i);
if (JSVAL_IS_TRACEABLE(v)) {
JS_SET_TRACING_DETAILS(trc, PrintObjectSlotName, obj, i);
JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
}
}
return LOCKED_OBJ_NSLOTS(obj);
}
void
@ -4846,8 +4924,8 @@ js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
* we rely on STOBJ_NSLOTS(obj) to get the number of available slots
* in obj after we allocate dynamic slots.
*
* See js_Mark, before the last return, where we make a special case
* for unmutated (scope->object != obj) objects.
* See js_TraceObject, before the slot tracing, where we make a special
* case for unmutated (scope->object != obj) objects.
*/
clasp = LOCKED_OBJ_GET_CLASS(obj);
nslots = JSSLOT_FREE(clasp);

View File

@ -357,7 +357,7 @@ js_LeaveSharpObject(JSContext *cx, JSIdArray **idap);
* and js_LeaveSharpObject. GC calls this when map->depth > 0.
*/
extern void
js_GCMarkSharpMap(JSContext *cx, JSSharpObjectMap *map);
js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map);
extern JSBool
js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
@ -563,7 +563,7 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp);
extern void
js_MarkNativeIteratorStates(JSContext *cx);
js_TraceNativeIteratorStates(JSTracer *trc);
extern JSBool
js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
@ -609,8 +609,8 @@ js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
extern JSBool
js_XDRObject(JSXDRState *xdr, JSObject **objp);
extern uint32
js_Mark(JSContext *cx, JSObject *obj, void *arg);
extern void
js_TraceObject(JSTracer *trc, JSObject *obj);
extern void
js_Clear(JSContext *cx, JSObject *obj);

View File

@ -130,6 +130,7 @@ typedef struct JSContext JSContext;
typedef struct JSErrorReport JSErrorReport;
typedef struct JSFunction JSFunction;
typedef struct JSFunctionSpec JSFunctionSpec;
typedef struct JSTracer JSTracer;
typedef struct JSIdArray JSIdArray;
typedef struct JSProperty JSProperty;
typedef struct JSPropertySpec JSPropertySpec;
@ -329,26 +330,75 @@ typedef JSBool
JSBool *bp);
/*
* Function type for JSClass.mark and JSObjectOps.mark, called from the GC to
* scan live GC-things reachable from obj's private data structure. For each
* such thing, a mark implementation must call
*
* JS_MarkGCThing(cx, thing, name, arg);
*
* The trailing name and arg parameters are used for GC_MARK_DEBUG-mode heap
* dumping and ref-path tracing. The mark function should pass a (typically
* literal) string naming the private data member for name, and it must pass
* the opaque arg parameter through from its caller.
*
* For the JSObjectOps.mark hook, the return value is the number of slots in
* obj to scan. For JSClass.mark, the return value is ignored.
*
* NB: JSMarkOp implementations cannot allocate new GC-things (JS_NewObject
* called from a mark function will fail silently, e.g.).
* Deprecated function type for JSClass.mark. All new code should define
* JSTraceOp instead to ensure the traversal of traceable things stored in
* the native structures.
*/
typedef uint32
(* JS_DLL_CALLBACK JSMarkOp)(JSContext *cx, JSObject *obj, void *arg);
/*
* Function type for trace operation of the class called to enumerate all
* traceable things reachable from obj's private data structure. For each such
* thing, a trace implementation must call
*
* JS_CallTracer(trc, thing, kind);
*
* or one of its convenience macros as described in jsapi.h.
*
* JSTraceOp implementation can assume that no other threads mutates object
* state. It must not change state of the object or corresponding native
* structures. The only exception for this rule is the case when the embedding
* needs a tight integration with GC. In that case the embedding can check if
* the traversal is a part of the marking phase through calling
* JS_IsGCMarkingTracer and apply a special code like emptying caches or
* marking its native structures.
*
* To define the tracer for a JSClass, the implementation must add
* JSCLASS_MARK_IS_TRACE to class flags and use JS_CLASS_TRACE(method)
* macro bellow to convert JSTraceOp to JSMarkOp when initializing or
* assigning JSClass.mark field.
*/
typedef void
(* JS_DLL_CALLBACK JSTraceOp)(JSTracer *trc, JSObject *obj);
#if defined __GNUC__ && __GNUC__ >= 4
# define JS_CLASS_TRACE(method) \
(__builtin_types_compatible_p(JSTraceOp, __typeof(&method)) \
? (JSMarkOp)(method) \
: JS_WrongTypeForClassTacer)
extern JSMarkOp JS_WrongTypeForClassTacer;
#else
# define JS_CLASS_TRACE(method) ((JSMarkOp)(method))
#endif
/*
* Tracer callback, called for each traceable thing directly refrenced 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_DOUBLE, 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 DEBUG-only JS_PrintTraceThingInfo.
*/
typedef void
(* JS_DLL_CALLBACK JSTraceCallback)(JSTracer *trc, void *thing, uint32 kind);
/*
* DEBUG only callback that JSTraceOp implementation can provide to return
* a string describing the reference traced with JS_CallTracer.
*/
#ifdef DEBUG
typedef void
(* JS_DLL_CALLBACK JSTraceNamePrinter)(JSTracer *trc, char *buf,
size_t bufsize);
#endif
/*
* The optional JSClass.reserveSlots hook allows a class to make computed
* per-instance object slots reservations, in addition to or instead of using

View File

@ -3848,19 +3848,20 @@ regexp_xdrObject(JSXDRState *xdr, JSObject **objp)
#endif /* !JS_HAS_XDR */
static uint32
regexp_mark(JSContext *cx, JSObject *obj, void *arg)
static void
regexp_trace(JSTracer *trc, JSObject *obj)
{
JSRegExp *re = (JSRegExp *) JS_GetPrivate(cx, obj);
if (re)
GC_MARK(cx, re->source, "source");
return 0;
JSRegExp *re;
re = (JSRegExp *) JS_GetPrivate(trc->context, obj);
if (re && re->source)
JS_CALL_STRING_TRACER(trc, re->source, "source");
}
JSClass js_RegExpClass = {
js_RegExp_str,
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
JS_PropertyStub, JS_PropertyStub,
regexp_getProperty, regexp_setProperty,
JS_EnumerateStub, JS_ResolveStub,
@ -3868,7 +3869,7 @@ JSClass js_RegExpClass = {
NULL, NULL,
regexp_call, NULL,
regexp_xdrObject, NULL,
regexp_mark, 0
JS_CLASS_TRACE(regexp_trace), 0
};
static const jschar empty_regexp_ucstr[] = {'(', '?', ':', ')', 0};

View File

@ -1494,65 +1494,76 @@ js_ClearScope(JSContext *cx, JSScope *scope)
}
void
js_MarkId(JSContext *cx, jsid id)
js_TraceId(JSTracer *trc, jsid id)
{
if (JSID_IS_ATOM(id))
GC_MARK_ATOM(cx, JSID_TO_ATOM(id));
else if (JSID_IS_OBJECT(id))
GC_MARK(cx, JSID_TO_OBJECT(id), "id");
else
JS_ASSERT(JSID_IS_INT(id));
JSObject *obj;
if (JSID_IS_ATOM(id)) {
JS_CALL_TRACER(trc, JSID_TO_ATOM(id), JSTRACE_ATOM, "id");
} else if (!JSID_IS_INT(id)) {
JS_ASSERT(JSID_IS_OBJECT(id));
obj = JSID_TO_OBJECT(id);
if (obj)
JS_CALL_OBJECT_TRACER(trc, obj, "id");
}
}
#if defined GC_MARK_DEBUG || defined DUMP_SCOPE_STATS
#if defined DEBUG || defined DUMP_SCOPE_STATS
# include "jsprf.h"
#endif
#ifdef DEBUG
static void
PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize)
{
JSScopeProperty *sprop;
size_t n;
const char *name;
JS_ASSERT(trc->debugPrinter == PrintPropertyGetterOrSetter);
sprop = (JSScopeProperty *)trc->debugPrintArg;
name = trc->debugPrintIndex ? js_setter_str : js_getter_str;
n = strlen(name);
if (JSID_IS_ATOM(sprop->id)) {
JSAtom *atom = JSID_TO_ATOM(sprop->id);
if (atom && ATOM_IS_STRING(atom)) {
n = js_PutEscapedString(buf, bufsize - 1,
ATOM_TO_STRING(atom), 0);
buf[n++] = ' ';
strncpy(buf + n, name, bufsize - n);
buf[bufsize - 1] = '\0';
} else {
JS_snprintf(buf, bufsize, "uknown %s", name);
}
} else if (JSID_IS_INT(sprop->id)) {
JS_snprintf(buf, bufsize, "%d %s", JSID_TO_INT(sprop->id), name);
} else {
JS_snprintf(buf, bufsize, "<object> %s", name);
}
}
#endif
void
js_MarkScopeProperty(JSContext *cx, JSScopeProperty *sprop)
js_TraceScopeProperty(JSTracer *trc, JSScopeProperty *sprop)
{
sprop->flags |= SPROP_MARK;
MARK_ID(cx, sprop->id);
TRACE_ID(trc, sprop->id);
#if JS_HAS_GETTER_SETTER
if (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
#ifdef GC_MARK_DEBUG
char buf[64];
size_t n;
if (JSID_IS_ATOM(sprop->id)) {
JSAtom *atom = JSID_TO_ATOM(sprop->id);
if (atom && ATOM_IS_STRING(atom)) {
n = js_PutEscapedString(buf, sizeof buf,
ATOM_TO_STRING(atom), 0);
} else {
static const char chars[] = "unknown";
JS_STATIC_ASSERT(sizeof(chars) <= sizeof buf);
memcpy(buf, chars, sizeof chars - 1);
n = sizeof chars - 1;
}
} else if (JSID_IS_INT(sprop->id)) {
n = JS_snprintf(buf, sizeof buf, "%d", JSID_TO_INT(sprop->id));
} else {
static const char chars[] = "<object>";
JS_STATIC_ASSERT(sizeof(chars) <= sizeof buf);
memcpy(buf, chars, sizeof chars - 1);
n = sizeof chars - 1;
}
#endif
if (sprop->attrs & JSPROP_GETTER) {
#ifdef GC_MARK_DEBUG
JS_snprintf(buf + n, sizeof buf - n, " %s", js_getter_str);
#endif
GC_MARK(cx, JSVAL_TO_GCTHING((jsval) sprop->getter), buf);
JS_ASSERT(JSVAL_IS_OBJECT((jsval) sprop->getter));
JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, sprop, 0);
JS_CallTracer(trc, JSVAL_TO_OBJECT((jsval) sprop->getter),
JSTRACE_OBJECT);
}
if (sprop->attrs & JSPROP_SETTER) {
#ifdef GC_MARK_DEBUG
JS_snprintf(buf + n, sizeof buf - n, " %s", js_setter_str);
#endif
GC_MARK(cx, JSVAL_TO_GCTHING((jsval) sprop->setter), buf);
JS_ASSERT(JSVAL_IS_OBJECT((jsval) sprop->setter));
JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, sprop, 1);
JS_CallTracer(trc, JSVAL_TO_OBJECT((jsval) sprop->setter),
JSTRACE_OBJECT);
}
}
#endif /* JS_HAS_GETTER_SETTER */

View File

@ -386,14 +386,14 @@ js_ClearScope(JSContext *cx, JSScope *scope);
* We retain them for internal backward compatibility, and in case one or both
* ever shrink to inline-able size.
*/
#define MARK_ID(cx,id) js_MarkId(cx, id)
#define MARK_SCOPE_PROPERTY(cx,sprop) js_MarkScopeProperty(cx, sprop)
#define TRACE_ID(trc, id) js_TraceId(trc, id)
#define TRACE_SCOPE_PROPERTY(trc, sprop) js_TraceScopeProperty(trc, sprop)
extern void
js_MarkId(JSContext *cx, jsid id);
js_TraceId(JSTracer *trc, jsid id);
extern void
js_MarkScopeProperty(JSContext *cx, JSScopeProperty *sprop);
js_TraceScopeProperty(JSTracer *trc, JSScopeProperty *sprop);
extern void
js_SweepScopeProperties(JSContext *cx);

View File

@ -926,15 +926,14 @@ script_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
#endif
}
static uint32
script_mark(JSContext *cx, JSObject *obj, void *arg)
static void
script_trace(JSTracer *trc, JSObject *obj)
{
JSScript *script;
script = (JSScript *) JS_GetPrivate(cx, obj);
script = (JSScript *) JS_GetPrivate(trc->context, obj);
if (script)
js_MarkScript(cx, script);
return 0;
js_TraceScript(trc, script);
}
#if !JS_HAS_SCRIPT_OBJECT
@ -943,12 +942,12 @@ script_mark(JSContext *cx, JSObject *obj, void *arg)
JS_FRIEND_DATA(JSClass) js_ScriptClass = {
js_Script_str,
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Script) |
JSCLASS_HAS_RESERVED_SLOTS(1),
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Script),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, script_finalize,
NULL, NULL, script_call, NULL,/*XXXbe xdr*/
NULL, NULL, script_mark, 0
NULL, NULL, JS_CLASS_TRACE(script_trace), NULL
};
#if JS_HAS_SCRIPT_OBJECT
@ -1472,7 +1471,7 @@ js_DestroyScript(JSContext *cx, JSScript *script)
}
void
js_MarkScript(JSContext *cx, JSScript *script)
js_TraceScript(JSTracer *trc, JSScript *script)
{
JSAtomMap *map;
uintN i, length;
@ -1482,9 +1481,9 @@ js_MarkScript(JSContext *cx, JSScript *script)
length = map->length;
vector = map->vector;
for (i = 0; i < length; i++)
GC_MARK_ATOM(cx, vector[i]);
JS_CALL_TRACER(trc, vector[i], JSTRACE_ATOM, "atom_table");
if (script->filename)
if (IS_GC_MARKING_TRACER(trc) && script->filename)
js_MarkScriptFilename(script->filename);
}

View File

@ -186,7 +186,7 @@ extern void
js_DestroyScript(JSContext *cx, JSScript *script);
extern void
js_MarkScript(JSContext *cx, JSScript *script);
js_TraceScript(JSTracer *trc, JSScript *script);
/*
* To perturb as little code as possible, we introduce a js_GetSrcNote lookup

View File

@ -4855,7 +4855,6 @@ Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
}
#if defined(DEBUG) || \
defined(GC_MARK_DEBUG) || \
defined(DUMP_CALL_TABLE) || \
defined(DUMP_SCOPE_STATS)
size_t

View File

@ -191,39 +191,28 @@ namespace_finalize(JSContext *cx, JSObject *obj)
}
static void
namespace_mark_vector(JSContext *cx, JSXMLNamespace **vec, uint32 len)
namespace_trace_vector(JSTracer *trc, JSXMLNamespace **vec,
uint32 len)
{
uint32 i;
JSXMLNamespace *ns;
for (i = 0; i < len; i++) {
ns = vec[i];
{
#ifdef GC_MARK_DEBUG
char buf[100];
size_t n;
n = ns->prefix
? js_PutEscapedString(buf, sizeof buf, ns->prefix, 0)
: 0;
if (n < sizeof buf - 1) {
buf[n++] = '=';
js_PutEscapedString(buf + n, sizeof buf - n, ns->uri, 0);
}
#endif
GC_MARK(cx, ns, buf);
if (ns) {
JS_SET_TRACING_INDEX(trc, "namespace_vector", i);
JS_CallTracer(trc, ns, JSTRACE_NAMESPACE);
}
}
}
static uint32
namespace_mark(JSContext *cx, JSObject *obj, void *arg)
static void
namespace_trace(JSTracer *trc, JSObject *obj)
{
JSXMLNamespace *ns;
ns = (JSXMLNamespace *) JS_GetPrivate(cx, obj);
GC_MARK(cx, ns, "private");
return 0;
ns = (JSXMLNamespace *) JS_GetPrivate(trc->context, obj);
JS_CALL_TRACER(trc, ns, JSTRACE_NAMESPACE, "private");
}
static JSBool
@ -247,11 +236,11 @@ namespace_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
JS_FRIEND_DATA(JSExtendedClass) js_NamespaceClass = {
{ "Namespace",
JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_CACHED_PROTO(JSProto_Namespace),
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Namespace),
JS_PropertyStub, JS_PropertyStub, namespace_getProperty, NULL,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, namespace_finalize,
NULL, NULL, NULL, NULL,
NULL, NULL, namespace_mark, NULL },
NULL, NULL, JS_CLASS_TRACE(namespace_trace), NULL },
namespace_equality,NULL, NULL, NULL,
NULL, NULL, NULL, NULL
};
@ -305,11 +294,14 @@ js_NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri,
}
void
js_MarkXMLNamespace(JSContext *cx, JSXMLNamespace *ns)
js_TraceXMLNamespace(JSTracer *trc, JSXMLNamespace *ns)
{
GC_MARK(cx, ns->object, "object");
GC_MARK(cx, ns->prefix, "prefix");
GC_MARK(cx, ns->uri, "uri");
if (ns->object)
JS_CALL_OBJECT_TRACER(trc, ns->object, "object");
if (ns->prefix)
JS_CALL_STRING_TRACER(trc, ns->prefix, "prefix");
if (ns->uri)
JS_CALL_STRING_TRACER(trc, ns->uri, "uri");
}
void
@ -409,14 +401,13 @@ anyname_finalize(JSContext* cx, JSObject* obj)
qname_finalize(cx, obj);
}
static uint32
qname_mark(JSContext *cx, JSObject *obj, void *arg)
static void
qname_trace(JSTracer *trc, JSObject *obj)
{
JSXMLQName *qn;
qn = (JSXMLQName *) JS_GetPrivate(cx, obj);
GC_MARK(cx, qn, "private");
return 0;
qn = (JSXMLQName *) JS_GetPrivate(trc->context, obj);
JS_CALL_TRACER(trc, qn, JSTRACE_QNAME, "private");
}
static JSBool
@ -450,11 +441,11 @@ qname_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
JS_FRIEND_DATA(JSExtendedClass) js_QNameClass = {
{ "QName",
JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_CACHED_PROTO(JSProto_QName),
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_QName),
JS_PropertyStub, JS_PropertyStub, qname_getProperty, NULL,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize,
NULL, NULL, NULL, NULL,
NULL, NULL, qname_mark, NULL },
NULL, NULL, JS_CLASS_TRACE(qname_trace), NULL },
qname_equality, NULL, NULL, NULL,
NULL, NULL, NULL, NULL
};
@ -468,21 +459,21 @@ JS_FRIEND_DATA(JSExtendedClass) js_QNameClass = {
JS_FRIEND_DATA(JSClass) js_AttributeNameClass = {
js_AttributeName_str,
JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE |
JSCLASS_HAS_CACHED_PROTO(JSProto_AttributeName),
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AttributeName),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize,
NULL, NULL, NULL, NULL,
NULL, NULL, qname_mark, NULL
NULL, NULL, JS_CLASS_TRACE(qname_trace), NULL
};
JS_FRIEND_DATA(JSClass) js_AnyNameClass = {
js_AnyName_str,
JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE |
JSCLASS_HAS_CACHED_PROTO(JSProto_AnyName),
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AnyName),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, anyname_finalize,
NULL, NULL, NULL, NULL,
NULL, NULL, qname_mark, NULL
NULL, NULL, JS_CLASS_TRACE(qname_trace), NULL
};
#define QNAME_ATTRS \
@ -573,12 +564,16 @@ js_NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix,
}
void
js_MarkXMLQName(JSContext *cx, JSXMLQName *qn)
js_TraceXMLQName(JSTracer *trc, JSXMLQName *qn)
{
GC_MARK(cx, qn->object, "object");
GC_MARK(cx, qn->uri, "uri");
GC_MARK(cx, qn->prefix, "prefix");
GC_MARK(cx, qn->localName, "localName");
if (qn->object)
JS_CALL_OBJECT_TRACER(trc, qn->object, "object");
if (qn->uri)
JS_CALL_STRING_TRACER(trc, qn->uri, "uri");
if (qn->prefix)
JS_CALL_STRING_TRACER(trc, qn->prefix, "prefix");
if (qn->localName)
JS_CALL_STRING_TRACER(trc, qn->localName, "localName");
}
void
@ -1043,15 +1038,24 @@ XMLArrayCursorItem(JSXMLArrayCursor *cursor)
}
static void
XMLArrayCursorMark(JSContext *cx, JSXMLArrayCursor *cursor)
XMLArrayCursorTrace(JSTracer *trc, JSXMLArrayCursor *cursor)
{
void *root;
#ifdef DEBUG
size_t index = 0;
#endif
while (cursor) {
GC_MARK(cx, cursor->root, "cursor->root");
root = cursor->root;
if (root) {
JS_SET_TRACING_INDEX(trc, "cursor_root", index++);
js_CallGCThingTracer(trc, root);
}
cursor = cursor->next;
}
}
/* NB: called with null cx from the GC, via xml_mark => XMLArrayTrim. */
/* NB: called with null cx from the GC, via xml_trace => XMLArrayTrim. */
static JSBool
XMLArraySetCapacity(JSContext *cx, JSXMLArray *array, uint32 capacity)
{
@ -4494,7 +4498,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
goto out;
}
nameobj = nameqn->object;
roots[ID_ROOT] = OBJECT_TO_JSVAL(nameqn);
roots[ID_ROOT] = OBJECT_TO_JSVAL(nameobj);
if (xml->xml_class == JSXML_CLASS_LIST) {
/*
@ -4987,40 +4991,16 @@ xml_finalize(JSContext *cx, JSObject *obj)
}
static void
xml_mark_vector(JSContext *cx, JSXML **vec, uint32 len)
xml_trace_vector(JSTracer *trc, JSXML **vec, uint32 len)
{
uint32 i;
JSXML *elt;
JSXML *xml;
for (i = 0; i < len; i++) {
elt = vec[i];
{
#ifdef GC_MARK_DEBUG
char buf[120];
size_t n;
if (elt->xml_class == JSXML_CLASS_LIST) {
strcpy(buf, js_XMLList_str);
} else if (JSXML_HAS_NAME(elt)) {
JSXMLQName *qn = elt->name;
if (qn->uri) {
n = js_PutEscapedString(buf, sizeof buf, qn->uri, 0);
} else {
buf[0] = '*';
n = 1;
}
if (n + 2 < sizeof buf) {
buf[n++] = ':';
buf[n++] = ':';
js_PutEscapedString(buf + n, sizeof buf - n, qn->localName,
0);
}
} else {
js_PutEscapedString(buf, sizeof buf, elt->xml_value, 0);
}
#endif
GC_MARK(cx, elt, buf);
xml = vec[i];
if (xml) {
JS_SET_TRACING_INDEX(trc, "xml_vector", i);
JS_CallTracer(trc, xml, JSTRACE_XML);
}
}
}
@ -5283,14 +5263,14 @@ xml_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
return JS_TRUE;
}
static uint32
xml_mark(JSContext *cx, JSObject *obj, void *arg)
static void
xml_trace(JSTracer *trc, JSObject *obj)
{
JSXML *xml;
xml = (JSXML *) JS_GetPrivate(cx, obj);
GC_MARK(cx, xml, "private");
return js_Mark(cx, obj, NULL);
xml = (JSXML *) JS_GetPrivate(trc->context, obj);
if (xml)
JS_CALL_TRACER(trc, xml, JSTRACE_XML, "private");
}
static void
@ -5552,7 +5532,7 @@ JS_FRIEND_DATA(JSXMLObjectOps) js_XMLObjectOps = {
NULL, NULL,
NULL, xml_hasInstance,
js_SetProtoOrParent, js_SetProtoOrParent,
xml_mark, xml_clear,
js_TraceObject, xml_clear,
NULL, NULL },
xml_getMethod, xml_setMethod,
xml_enumerateValues, xml_equality,
@ -5567,11 +5547,12 @@ xml_getObjectOps(JSContext *cx, JSClass *clasp)
JS_FRIEND_DATA(JSClass) js_XMLClass = {
js_XML_str,
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_XML),
JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE |
JSCLASS_HAS_CACHED_PROTO(JSProto_XML),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, xml_finalize,
xml_getObjectOps, NULL, NULL, NULL,
NULL, NULL, NULL, NULL
NULL, NULL, JS_CLASS_TRACE(xml_trace), NULL
};
static JSObject *
@ -6146,16 +6127,15 @@ typedef struct JSTempRootedNSArray {
} JSTempRootedNSArray;
JS_STATIC_DLL_CALLBACK(void)
mark_temp_ns_array(JSContext *cx, JSTempValueRooter *tvr)
trace_temp_ns_array(JSTracer *trc, JSTempValueRooter *tvr)
{
JSTempRootedNSArray *tmp = (JSTempRootedNSArray *)tvr;
namespace_mark_vector(cx,
(JSXMLNamespace **)tmp->array.vector,
tmp->array.length);
XMLArrayCursorMark(cx, tmp->array.cursors);
if (JSVAL_IS_GCTHING(tmp->value))
GC_MARK(cx, JSVAL_TO_GCTHING(tmp->value), "temp_ns_array_value");
namespace_trace_vector(trc,
(JSXMLNamespace **)tmp->array.vector,
tmp->array.length);
XMLArrayCursorTrace(trc, tmp->array.cursors);
JS_CALL_VALUE_TRACER(trc, tmp->value, "temp_ns_array_value");
}
static void
@ -6163,13 +6143,13 @@ InitTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp)
{
XMLArrayInit(cx, &tmp->array, 0);
tmp->value = JSVAL_NULL;
JS_PUSH_TEMP_ROOT_MARKER(cx, mark_temp_ns_array, &tmp->tvr);
JS_PUSH_TEMP_ROOT_TRACE(cx, trace_temp_ns_array, &tmp->tvr);
}
static void
FinishTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp)
{
JS_ASSERT(tmp->tvr.u.marker == mark_temp_ns_array);
JS_ASSERT(tmp->tvr.u.trace == trace_temp_ns_array);
JS_POP_TEMP_ROOT(cx, &tmp->tvr);
XMLArrayFinish(cx, &tmp->array);
}
@ -6495,7 +6475,7 @@ out:
static const char js_attribute_str[] = "attribute";
static const char js_text_str[] = "text";
/* Exported to jsgc.c #ifdef GC_MARK_DEBUG. */
/* Exported to jsgc.c #ifdef DEBUG. */
const char *js_xml_class_str[] = {
"list",
"element",
@ -7452,40 +7432,49 @@ js_NewXML(JSContext *cx, JSXMLClass xml_class)
}
void
js_MarkXML(JSContext *cx, JSXML *xml)
js_TraceXML(JSTracer *trc, JSXML *xml)
{
GC_MARK(cx, xml->object, "object");
GC_MARK(cx, xml->name, "name");
GC_MARK(cx, xml->parent, "xml_parent");
if (xml->object)
JS_CALL_OBJECT_TRACER(trc, xml->object, "object");
if (xml->name)
JS_CALL_TRACER(trc, xml->name, JSTRACE_QNAME, "name");
if (xml->parent)
JS_CALL_TRACER(trc, xml->parent, JSTRACE_XML, "xml_parent");
if (JSXML_HAS_VALUE(xml)) {
GC_MARK(cx, xml->xml_value, "value");
if (xml->xml_value)
JS_CALL_STRING_TRACER(trc, xml->xml_value, "value");
return;
}
xml_mark_vector(cx,
(JSXML **) xml->xml_kids.vector,
xml->xml_kids.length);
XMLArrayCursorMark(cx, xml->xml_kids.cursors);
XMLArrayTrim(&xml->xml_kids);
xml_trace_vector(trc,
(JSXML **) xml->xml_kids.vector,
xml->xml_kids.length);
XMLArrayCursorTrace(trc, xml->xml_kids.cursors);
if (IS_GC_MARKING_TRACER(trc))
XMLArrayTrim(&xml->xml_kids);
if (xml->xml_class == JSXML_CLASS_LIST) {
if (xml->xml_target)
GC_MARK(cx, xml->xml_target, "target");
if (xml->xml_targetprop)
GC_MARK(cx, xml->xml_targetprop, "targetprop");
JS_CALL_TRACER(trc, xml->xml_target, JSTRACE_XML, "target");
if (xml->xml_targetprop) {
JS_CALL_TRACER(trc, xml->xml_targetprop, JSTRACE_QNAME,
"targetprop");
}
} else {
namespace_mark_vector(cx,
(JSXMLNamespace **) xml->xml_namespaces.vector,
xml->xml_namespaces.length);
XMLArrayCursorMark(cx, xml->xml_namespaces.cursors);
XMLArrayTrim(&xml->xml_namespaces);
namespace_trace_vector(trc,
(JSXMLNamespace **)xml->xml_namespaces.vector,
xml->xml_namespaces.length);
XMLArrayCursorTrace(trc, xml->xml_namespaces.cursors);
if (IS_GC_MARKING_TRACER(trc))
XMLArrayTrim(&xml->xml_namespaces);
xml_mark_vector(cx,
(JSXML **) xml->xml_attrs.vector,
xml->xml_attrs.length);
XMLArrayCursorMark(cx, xml->xml_attrs.cursors);
XMLArrayTrim(&xml->xml_attrs);
xml_trace_vector(trc,
(JSXML **) xml->xml_attrs.vector,
xml->xml_attrs.length);
XMLArrayCursorTrace(trc, xml->xml_attrs.cursors);
if (IS_GC_MARKING_TRACER(trc))
XMLArrayTrim(&xml->xml_attrs);
}
}

View File

@ -64,7 +64,7 @@ js_NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri,
JSBool declared);
extern void
js_MarkXMLNamespace(JSContext *cx, JSXMLNamespace *ns);
js_TraceXMLNamespace(JSTracer *trc, JSXMLNamespace *ns);
extern void
js_FinalizeXMLNamespace(JSContext *cx, JSXMLNamespace *ns);
@ -88,7 +88,7 @@ js_NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix,
JSString *localName);
extern void
js_MarkXMLQName(JSContext *cx, JSXMLQName *qn);
js_TraceXMLQName(JSTracer *trc, JSXMLQName *qn);
extern void
js_FinalizeXMLQName(JSContext *cx, JSXMLQName *qn);
@ -203,7 +203,7 @@ extern JSXML *
js_NewXML(JSContext *cx, JSXMLClass xml_class);
extern void
js_MarkXML(JSContext *cx, JSXML *xml);
js_TraceXML(JSTracer *trc, JSXML *xml);
extern void
js_FinalizeXML(JSContext *cx, JSXML *xml);