зеркало из https://github.com/mozilla/pjs.git
Bug 375270: API to trace GC things graph without running the GC. r=brendan
This commit is contained in:
Родитель
1feb40e704
Коммит
b14781090f
93
js/src/js.c
93
js/src/js.c
|
@ -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},
|
||||
|
|
|
@ -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 *)
|
||||
|
|
181
js/src/jsapi.h
181
js/src/jsapi.h
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
1300
js/src/jsgc.c
1300
js/src/jsgc.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
112
js/src/jsobj.c
112
js/src/jsobj.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
223
js/src/jsxml.c
223
js/src/jsxml.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче