mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 10:15:41 +00:00
Bug 357169: temp root macros are type-safe now and details of AddRoot etc. implementation do not leak ouside jsgc.c. r=brendan
This commit is contained in:
parent
8c58a3686e
commit
848e7ed2e3
@ -1795,84 +1795,22 @@ JS_ForgetLocalRoot(JSContext *cx, void *thing)
|
||||
js_ForgetLocalRoot(cx, (jsval) thing);
|
||||
}
|
||||
|
||||
#include "jshash.h" /* Added by JSIFY */
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
typedef struct NamedRootDumpArgs {
|
||||
void (*dump)(const char *name, void *rp, void *data);
|
||||
void *data;
|
||||
} NamedRootDumpArgs;
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
|
||||
js_named_root_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
|
||||
void *arg)
|
||||
{
|
||||
NamedRootDumpArgs *args = (NamedRootDumpArgs *) arg;
|
||||
JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
|
||||
|
||||
if (rhe->name)
|
||||
args->dump(rhe->name, rhe->root, args->data);
|
||||
return JS_DHASH_NEXT;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_DumpNamedRoots(JSRuntime *rt,
|
||||
void (*dump)(const char *name, void *rp, void *data),
|
||||
void *data)
|
||||
{
|
||||
NamedRootDumpArgs args;
|
||||
|
||||
args.dump = dump;
|
||||
args.data = data;
|
||||
JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args);
|
||||
return js_DumpNamedRoots(rt, dump, data);
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
typedef struct GCRootMapArgs {
|
||||
JSGCRootMapFun map;
|
||||
void *data;
|
||||
} GCRootMapArgs;
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
|
||||
js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
|
||||
void *arg)
|
||||
{
|
||||
GCRootMapArgs *args = (GCRootMapArgs *) arg;
|
||||
JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
|
||||
intN mapflags;
|
||||
JSDHashOperator op;
|
||||
|
||||
mapflags = args->map(rhe->root, rhe->name, args->data);
|
||||
|
||||
#if JS_MAP_GCROOT_NEXT == JS_DHASH_NEXT && \
|
||||
JS_MAP_GCROOT_STOP == JS_DHASH_STOP && \
|
||||
JS_MAP_GCROOT_REMOVE == JS_DHASH_REMOVE
|
||||
op = (JSDHashOperator)mapflags;
|
||||
#else
|
||||
op = JS_DHASH_NEXT;
|
||||
if (mapflags & JS_MAP_GCROOT_STOP)
|
||||
op |= JS_DHASH_STOP;
|
||||
if (mapflags & JS_MAP_GCROOT_REMOVE)
|
||||
op |= JS_DHASH_REMOVE;
|
||||
#endif
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(uint32)
|
||||
JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
|
||||
{
|
||||
GCRootMapArgs args;
|
||||
uint32 rv;
|
||||
|
||||
args.map = map;
|
||||
args.data = data;
|
||||
JS_LOCK_GC(rt);
|
||||
rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
|
||||
JS_UNLOCK_GC(rt);
|
||||
return rv;
|
||||
return JS_MapGCRoots(rt, map, data);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
@ -2218,7 +2156,7 @@ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
|
||||
return NULL;
|
||||
|
||||
/* After this point, control must exit via label bad or out. */
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, proto, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr);
|
||||
|
||||
if (!constructor) {
|
||||
/*
|
||||
|
@ -423,7 +423,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Protect iter against GC in OBJ_DELETE_PROPERTY. */
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, iter, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr);
|
||||
gap = oldlen - newlen;
|
||||
for (;;) {
|
||||
ok = JS_NextProperty(cx, iter, &id2);
|
||||
|
@ -465,6 +465,8 @@ typedef void
|
||||
typedef union JSTempValueUnion {
|
||||
jsval value;
|
||||
JSObject *object;
|
||||
JSString *string;
|
||||
void *gcthing;
|
||||
JSTempValueMarker marker;
|
||||
jsval *array;
|
||||
} JSTempValueUnion;
|
||||
@ -479,24 +481,27 @@ 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 to root.
|
||||
* 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 that is executed to mark
|
||||
* the values.
|
||||
* If count >= 0, then u.array points to a stack-allocated vector of jsvals.
|
||||
*
|
||||
* To root a single GC-thing pointer, which need not be tagged and stored as a
|
||||
* jsval, use JS_PUSH_SINGLE_TEMP_ROOT. The (jsval)(val) cast works because a
|
||||
* GC-thing is aligned on a 0 mod 8 boundary, and object has the 0 jsval tag.
|
||||
* So any GC-thing may be tagged as if it were an object and untagged, if it's
|
||||
* then used only as an opaque pointer until discriminated by other means than
|
||||
* tag bits (this is how the GC mark function uses its |thing| parameter -- it
|
||||
* consults GC-thing flags stored separately from the thing to decide the type
|
||||
* of thing).
|
||||
* jsval, use JS_PUSH_TEMP_ROOT_GCTHING. The macro reinterprets an arbitrary
|
||||
* GC-thing as jsval. It works because a GC-thing is aligned on a 0 mod 8
|
||||
* boundary, and object has the 0 jsval tag. So any GC-thing may be tagged as
|
||||
* if it were an object and untagged, if it's then used only as an opaque
|
||||
* pointer until discriminated by other means than tag bits (this is how the
|
||||
* GC mark function uses its |thing| parameter -- it consults GC-thing flags
|
||||
* stored separately from the thing to decide the type of thing).
|
||||
*
|
||||
* Alternatively, if a single pointer to rooted JSObject * is required, use
|
||||
* JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr). Then &tvr.u.object gives the
|
||||
* necessary pointer, which puns tvr.u.value safely because object tag bits
|
||||
* are all zeroes.
|
||||
* JS_PUSH_TEMP_ROOT_OBJECT and JS_PUSH_TEMP_ROOT_STRING are type-safe
|
||||
* alternatives to JS_PUSH_TEMP_ROOT_GCTHING for JSObject and JSString. They
|
||||
* also provide a simple way to get a single pointer to rooted JSObject or
|
||||
* JSString via JS_PUSH_TEMP_ROOT_(OBJECT|STRTING)(cx, NULL, &tvr). Then
|
||||
* &tvr.u.object or tvr.u.string gives the necessary pointer, which puns
|
||||
* tvr.u.value safely because JSObject * and JSString * are GC-things and, as
|
||||
* such, their tag bits are all zeroes.
|
||||
*
|
||||
* If you need to protect a result value that flows out of a C function across
|
||||
* several layers of other functions, use the js_LeaveLocalRootScopeWithResult
|
||||
@ -517,31 +522,46 @@ struct JSTempValueRooter {
|
||||
|
||||
#define JS_PUSH_SINGLE_TEMP_ROOT(cx,val,tvr) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
(tvr)->count = -1; \
|
||||
(tvr)->u.value = (jsval)(val); \
|
||||
(tvr)->u.value = val; \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_PUSH_TEMP_ROOT(cx,cnt,arr,tvr) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
JS_ASSERT((ptrdiff_t)(cnt) >= 0); \
|
||||
(tvr)->count = (ptrdiff_t)(cnt); \
|
||||
(tvr)->u.array = (arr); \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_PUSH_TEMP_ROOT_MARKER(cx,marker_,tvr) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
(tvr)->count = -2; \
|
||||
(tvr)->u.marker = (marker_); \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_PUSH_TEMP_ROOT_OBJECT(cx,obj,tvr) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
(tvr)->count = -1; \
|
||||
(tvr)->u.object = (obj); \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_PUSH_TEMP_ROOT_STRING(cx,str,tvr) \
|
||||
JS_BEGIN_MACRO \
|
||||
(tvr)->count = -1; \
|
||||
(tvr)->u.string = (str); \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_PUSH_TEMP_ROOT_GCTHING(cx,thing,tvr) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_ASSERT(JSVAL_IS_OBJECT((jsval)thing)); \
|
||||
(tvr)->count = -1; \
|
||||
(tvr)->u.gcthing = (thing); \
|
||||
JS_PUSH_TEMP_ROOT_COMMON(cx, tvr); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_POP_TEMP_ROOT(cx,tvr) \
|
||||
|
@ -1253,9 +1253,10 @@ out:
|
||||
JSBool
|
||||
js_ReportUncaughtException(JSContext *cx)
|
||||
{
|
||||
jsval exn, *vp;
|
||||
jsval exn;
|
||||
JSObject *exnObject;
|
||||
void *mark;
|
||||
jsval vp[5];
|
||||
JSTempValueRooter tvr;
|
||||
JSErrorReport *reportp, report;
|
||||
JSString *str;
|
||||
const char *bytes;
|
||||
@ -1275,18 +1276,11 @@ js_ReportUncaughtException(JSContext *cx)
|
||||
*/
|
||||
if (JSVAL_IS_PRIMITIVE(exn)) {
|
||||
exnObject = NULL;
|
||||
vp = NULL;
|
||||
#ifdef __GNUC__ /* suppress bogus gcc warnings */
|
||||
mark = NULL;
|
||||
#endif
|
||||
} else {
|
||||
exnObject = JSVAL_TO_OBJECT(exn);
|
||||
vp = js_AllocStack(cx, 5, &mark);
|
||||
if (!vp) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
vp[0] = exn;
|
||||
memset(vp + 1, 0, sizeof vp - sizeof vp[0]);
|
||||
JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(vp), vp, &tvr);
|
||||
}
|
||||
|
||||
JS_ClearPendingException(cx);
|
||||
@ -1297,7 +1291,7 @@ js_ReportUncaughtException(JSContext *cx)
|
||||
if (!str) {
|
||||
bytes = "unknown (can't convert to string)";
|
||||
} else {
|
||||
if (vp)
|
||||
if (exnObject)
|
||||
vp[1] = STRING_TO_JSVAL(str);
|
||||
bytes = js_GetStringBytes(cx->runtime, str);
|
||||
}
|
||||
@ -1349,6 +1343,6 @@ js_ReportUncaughtException(JSContext *cx)
|
||||
|
||||
out:
|
||||
if (exnObject)
|
||||
js_FreeStack(cx, mark);
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
return ok;
|
||||
}
|
||||
|
@ -1260,7 +1260,7 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
||||
}
|
||||
|
||||
/* From here on, control flow must flow through label out. */
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, fun->object, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, fun->object, &tvr);
|
||||
ok = JS_TRUE;
|
||||
|
||||
if (!JS_XDRUint32(xdr, &nullAtom))
|
||||
@ -2299,7 +2299,7 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
|
||||
*vp,
|
||||
NULL);
|
||||
if (str) {
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, str, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_STRING(cx, str, &tvr);
|
||||
bytes = JS_GetStringBytes(str);
|
||||
if (flags & JSV2F_ITERATOR) {
|
||||
source = js_ValueToPrintableSource(cx, *vp);
|
||||
|
166
js/src/jsgc.c
166
js/src/jsgc.c
@ -591,6 +591,13 @@ js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This is compatible with JSDHashEntryStub. */
|
||||
typedef struct JSGCRootHashEntry {
|
||||
JSDHashEntryHdr hdr;
|
||||
void *root;
|
||||
const char *name;
|
||||
} JSGCRootHashEntry;
|
||||
|
||||
/* Initial size of the gcRootsHash table (SWAG, small enough to amortize). */
|
||||
#define GC_ROOTS_SIZE 256
|
||||
#define GC_FINALIZE_LEN 1024
|
||||
@ -705,19 +712,8 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
|
||||
js_root_printer(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 i, void *arg)
|
||||
{
|
||||
uint32 *leakedroots = (uint32 *)arg;
|
||||
JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
|
||||
|
||||
(*leakedroots)++;
|
||||
fprintf(stderr,
|
||||
"JS engine warning: leaking GC root \'%s\' at %p\n",
|
||||
rhe->name ? (char *)rhe->name : "", rhe->root);
|
||||
|
||||
return JS_DHASH_NEXT;
|
||||
}
|
||||
static void
|
||||
CheckLeakedRoots(JSRuntime *rt);
|
||||
#endif
|
||||
|
||||
void
|
||||
@ -740,27 +736,8 @@ js_FinishGC(JSRuntime *rt)
|
||||
|
||||
if (rt->gcRootsHash.ops) {
|
||||
#ifdef DEBUG
|
||||
uint32 leakedroots = 0;
|
||||
|
||||
/* Warn (but don't assert) debug builds of any remaining roots. */
|
||||
JS_DHashTableEnumerate(&rt->gcRootsHash, js_root_printer,
|
||||
&leakedroots);
|
||||
if (leakedroots > 0) {
|
||||
if (leakedroots == 1) {
|
||||
fprintf(stderr,
|
||||
"JS engine warning: 1 GC root remains after destroying the JSRuntime.\n"
|
||||
" This root may point to freed memory. Objects reachable\n"
|
||||
" through it have not been finalized.\n");
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"JS engine warning: %lu GC roots remain after destroying the JSRuntime.\n"
|
||||
" These roots may point to freed memory. Objects reachable\n"
|
||||
" through them have not been finalized.\n",
|
||||
(unsigned long) leakedroots);
|
||||
}
|
||||
}
|
||||
CheckLeakedRoots(rt);
|
||||
#endif
|
||||
|
||||
JS_DHashTableFinish(&rt->gcRootsHash);
|
||||
rt->gcRootsHash.ops = NULL;
|
||||
}
|
||||
@ -842,6 +819,122 @@ js_RemoveRoot(JSRuntime *rt, void *rp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
|
||||
js_root_printer(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 i, void *arg)
|
||||
{
|
||||
uint32 *leakedroots = (uint32 *)arg;
|
||||
JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
|
||||
|
||||
(*leakedroots)++;
|
||||
fprintf(stderr,
|
||||
"JS engine warning: leaking GC root \'%s\' at %p\n",
|
||||
rhe->name ? (char *)rhe->name : "", rhe->root);
|
||||
|
||||
return JS_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static void
|
||||
CheckLeakedRoots(JSRuntime *rt)
|
||||
{
|
||||
uint32 leakedroots = 0;
|
||||
|
||||
/* Warn (but don't assert) debug builds of any remaining roots. */
|
||||
JS_DHashTableEnumerate(&rt->gcRootsHash, js_root_printer,
|
||||
&leakedroots);
|
||||
if (leakedroots > 0) {
|
||||
if (leakedroots == 1) {
|
||||
fprintf(stderr,
|
||||
"JS engine warning: 1 GC root remains after destroying the JSRuntime.\n"
|
||||
" This root may point to freed memory. Objects reachable\n"
|
||||
" through it have not been finalized.\n");
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"JS engine warning: %lu GC roots remain after destroying the JSRuntime.\n"
|
||||
" These roots may point to freed memory. Objects reachable\n"
|
||||
" through them have not been finalized.\n",
|
||||
(unsigned long) leakedroots);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct NamedRootDumpArgs {
|
||||
void (*dump)(const char *name, void *rp, void *data);
|
||||
void *data;
|
||||
} NamedRootDumpArgs;
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
|
||||
js_named_root_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
|
||||
void *arg)
|
||||
{
|
||||
NamedRootDumpArgs *args = (NamedRootDumpArgs *) arg;
|
||||
JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
|
||||
|
||||
if (rhe->name)
|
||||
args->dump(rhe->name, rhe->root, args->data);
|
||||
return JS_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
js_DumpNamedRoots(JSRuntime *rt,
|
||||
void (*dump)(const char *name, void *rp, void *data),
|
||||
void *data)
|
||||
{
|
||||
NamedRootDumpArgs args;
|
||||
|
||||
args.dump = dump;
|
||||
args.data = data;
|
||||
JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args);
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
typedef struct GCRootMapArgs {
|
||||
JSGCRootMapFun map;
|
||||
void *data;
|
||||
} GCRootMapArgs;
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
|
||||
js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
|
||||
void *arg)
|
||||
{
|
||||
GCRootMapArgs *args = (GCRootMapArgs *) arg;
|
||||
JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
|
||||
intN mapflags;
|
||||
JSDHashOperator op;
|
||||
|
||||
mapflags = args->map(rhe->root, rhe->name, args->data);
|
||||
|
||||
#if JS_MAP_GCROOT_NEXT == JS_DHASH_NEXT && \
|
||||
JS_MAP_GCROOT_STOP == JS_DHASH_STOP && \
|
||||
JS_MAP_GCROOT_REMOVE == JS_DHASH_REMOVE
|
||||
op = (JSDHashOperator)mapflags;
|
||||
#else
|
||||
op = JS_DHASH_NEXT;
|
||||
if (mapflags & JS_MAP_GCROOT_STOP)
|
||||
op |= JS_DHASH_STOP;
|
||||
if (mapflags & JS_MAP_GCROOT_REMOVE)
|
||||
op |= JS_DHASH_REMOVE;
|
||||
#endif
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
uint32
|
||||
js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
|
||||
{
|
||||
GCRootMapArgs args;
|
||||
uint32 rv;
|
||||
|
||||
args.map = map;
|
||||
args.data = data;
|
||||
JS_LOCK_GC(rt);
|
||||
rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
|
||||
JS_UNLOCK_GC(rt);
|
||||
return rv;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_RegisterCloseableIterator(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
@ -1523,6 +1616,13 @@ js_LockGCThing(JSContext *cx, void *thing)
|
||||
|
||||
#define GC_THING_IS_DEEP(t,o) (GC_TYPE_IS_DEEP(t) || IS_DEEP_STRING(t, o))
|
||||
|
||||
/* This is compatible with JSDHashEntryStub. */
|
||||
typedef struct JSGCLockHashEntry {
|
||||
JSDHashEntryHdr hdr;
|
||||
const JSGCThing *thing;
|
||||
uint32 count;
|
||||
} JSGCLockHashEntry;
|
||||
|
||||
JSBool
|
||||
js_LockGCThingRT(JSRuntime *rt, void *thing)
|
||||
{
|
||||
|
@ -88,19 +88,6 @@ js_GetGCThingFlags(void *thing);
|
||||
JSRuntime*
|
||||
js_GetGCStringRuntime(JSString *str);
|
||||
|
||||
/* These are compatible with JSDHashEntryStub. */
|
||||
struct JSGCRootHashEntry {
|
||||
JSDHashEntryHdr hdr;
|
||||
void *root;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct JSGCLockHashEntry {
|
||||
JSDHashEntryHdr hdr;
|
||||
const JSGCThing *thing;
|
||||
uint32 count;
|
||||
};
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* Since we're forcing a GC from JS_GC anyway, don't bother wasting cycles
|
||||
@ -131,6 +118,16 @@ js_AddRootRT(JSRuntime *rt, void *rp, const char *name);
|
||||
extern JSBool
|
||||
js_RemoveRoot(JSRuntime *rt, void *rp);
|
||||
|
||||
#ifdef DEBUG
|
||||
extern void
|
||||
js_DumpNamedRoots(JSRuntime *rt,
|
||||
void (*dump)(const char *name, void *rp, void *data),
|
||||
void *data);
|
||||
#endif
|
||||
|
||||
extern uint32
|
||||
js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data);
|
||||
|
||||
/* Table of pointers with count valid members. */
|
||||
typedef struct JSPtrTable {
|
||||
size_t count;
|
||||
|
@ -526,7 +526,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
||||
obj = cursor;
|
||||
if (!parent)
|
||||
break;
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, obj, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
|
||||
} else {
|
||||
/*
|
||||
* Avoid OBJ_SET_PARENT overhead as clonedChild cannot escape to
|
||||
|
@ -2348,7 +2348,7 @@ js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
|
||||
* GC calling JS_ClearNewbornRoots. There's also the possibilty of things
|
||||
* happening under the objectHook call-out further below.
|
||||
*/
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, obj, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
|
||||
|
||||
/*
|
||||
* Share proto's map only if it has the same JSObjectOps, and only if
|
||||
|
@ -91,8 +91,6 @@ typedef uint32 jsatomid;
|
||||
typedef struct JSArgumentFormatMap JSArgumentFormatMap;
|
||||
typedef struct JSCodeGenerator JSCodeGenerator;
|
||||
typedef struct JSDependentString JSDependentString;
|
||||
typedef struct JSGCLockHashEntry JSGCLockHashEntry;
|
||||
typedef struct JSGCRootHashEntry JSGCRootHashEntry;
|
||||
typedef struct JSGCThing JSGCThing;
|
||||
typedef struct JSGenerator JSGenerator;
|
||||
typedef struct JSParseNode JSParseNode;
|
||||
|
@ -4149,7 +4149,7 @@ js_NewRegExpObject(JSContext *cx, JSTokenStream *ts,
|
||||
re = js_NewRegExp(cx, ts, str, flags, JS_FALSE);
|
||||
if (!re)
|
||||
return NULL;
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, str, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_STRING(cx, str, &tvr);
|
||||
obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);
|
||||
if (!obj || !JS_SetPrivate(cx, obj, re)) {
|
||||
js_DestroyRegExp(cx, re);
|
||||
|
@ -531,6 +531,7 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
|
||||
uintN errorNumber, JSErrorReport *report,
|
||||
JSBool charArgs, va_list ap)
|
||||
{
|
||||
JSTempValueRooter linetvr;
|
||||
JSString *linestr = NULL;
|
||||
JSTokenStream *ts = NULL;
|
||||
JSCodeGenerator *cg = NULL;
|
||||
@ -553,7 +554,7 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
js_AddRoot(cx, &linestr, "error line buffer");
|
||||
JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &linetvr);
|
||||
|
||||
switch (flags & JSREPORT_HANDLE) {
|
||||
case JSREPORT_TS:
|
||||
@ -588,6 +589,7 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
|
||||
ts->linebuf.base,
|
||||
jschar),
|
||||
0);
|
||||
linetvr.u.string = linestr;
|
||||
report->linebuf = linestr
|
||||
? JS_GetStringBytes(linestr)
|
||||
: NULL;
|
||||
@ -693,7 +695,7 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
|
||||
if (report->ucmessage)
|
||||
JS_free(cx, (void *)report->ucmessage);
|
||||
|
||||
js_RemoveRoot(cx->runtime, &linestr);
|
||||
JS_POP_TEMP_ROOT(cx, &linetvr);
|
||||
|
||||
if (ts && !JSREPORT_IS_WARNING(flags)) {
|
||||
/* Set the error flag to suppress spurious reports. */
|
||||
|
@ -3101,7 +3101,7 @@ ToAttributeName(JSContext *cx, jsval v)
|
||||
if (!qn)
|
||||
return NULL;
|
||||
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, qn, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_GCTHING(cx, qn, &tvr);
|
||||
obj = js_GetAttributeNameObject(cx, qn);
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
if (!obj)
|
||||
@ -7630,7 +7630,7 @@ js_NewXMLObject(JSContext *cx, JSXMLClass xml_class)
|
||||
xml = js_NewXML(cx, xml_class);
|
||||
if (!xml)
|
||||
return NULL;
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, xml, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_GCTHING(cx, xml, &tvr);
|
||||
obj = js_GetXMLObject(cx, xml);
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
return obj;
|
||||
|
Loading…
Reference in New Issue
Block a user