Clean up JSObjectOps layering violations by adding mark and clear ops; JSClass gets a corresponding mark op so classes with unregistered roots in private data can mark them. The JS API gets a new JS_MarkGCThing entry point for JSObjectOps.mark implementors. Prerequisite check-in for bug 49816 and others (r=shaver).

This commit is contained in:
brendan%mozilla.org 2000-08-26 02:30:22 +00:00
parent 1196739ccc
commit c77f05ae2e
21 changed files with 380 additions and 285 deletions

View File

@ -18,7 +18,7 @@
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
@ -140,7 +140,7 @@ int fputs(const char *s, FILE *file)
char buffer[4096];
int n = strlen(s);
int extra = 0;
while (n > sizeof buffer) {
memcpy(buffer, s, sizeof buffer);
translateLFtoCR(buffer, sizeof buffer);
@ -629,7 +629,7 @@ Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
static JSBool
Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
int r = 0;
int r = 0;
#ifdef LIVECONNECT
JSJ_SimpleShutdown();
@ -1336,6 +1336,15 @@ BuildDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_TRUE;
}
static JSBool
Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
if (argc != 0 && !JS_ValueToObject(cx, argv[0], &obj))
return JS_FALSE;
JS_ClearScope(cx, obj);
return JS_TRUE;
}
static JSFunctionSpec shell_functions[] = {
{"version", Version, 0},
{"options", Options, 0},
@ -1362,6 +1371,7 @@ static JSFunctionSpec shell_functions[] = {
{"cvtargs", ConvertArgs, 0, 0, 12},
#endif
{"build", BuildDate, 0},
{"clear", Clear, 0},
{0}
};

View File

@ -958,7 +958,7 @@ InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
if (!cx->globalObject)
cx->globalObject = obj;
/* Record both Function and Object in resolving, if we are resolving. */
/* Record both Function and Object in cx->resolving, if we are resolving. */
table = cx->resolving;
if (table) {
rt = cx->runtime;
@ -1047,7 +1047,7 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
#define TAG_ATOM_OFFSET(name) ((const char *) ATOM_OFFSET(name))
#define TAG_CHAR_STRING(name) name
#define UNTAG_ATOM_OFFSET(ptr) ((size_t) (ptr))
#define UNTAG_ATOM_OFFSET(ptr) ((size_t)(ptr))
#define UNTAG_CHAR_STRING(ptr) ptr
#define IS_ATOM_OFFSET(ptr) ((size_t)(ptr) < sizeof(JSAtomState))
@ -1490,6 +1490,17 @@ JS_UnlockGCThing(JSContext *cx, void *thing)
return ok;
}
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 == js_CurrentThreadId());
#endif
GC_MARK(cx, thing, name, arg);
}
JS_PUBLIC_API(void)
JS_GC(JSContext *cx)
{
@ -2433,25 +2444,10 @@ JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
JS_PUBLIC_API(void)
JS_ClearScope(JSContext *cx, JSObject *obj)
{
JSObjectMap *map;
JSScope *scope;
uint32 i;
CHECK_REQUEST(cx);
/* XXXbe push this into jsobj.c or jsscope.c */
/* XXXbe2 worse, assumes obj is native here, before MAP_IS_NATIVE! */
JS_LOCK_OBJ(cx, obj);
map = obj->map;
if (MAP_IS_NATIVE(map)) {
scope = (JSScope *)map;
scope->ops->clear(cx, scope);
}
/* Clear slot values and reset freeslot so we're consistent. */
map->freeslot = JSSLOT_FREE(OBJ_GET_CLASS(cx, obj));
for (i = map->nslots-1; i >= map->freeslot; --i)
obj->slots[i] = JSVAL_VOID;
JS_UNLOCK_OBJ(cx, obj);
if (obj->map->ops->clear)
obj->map->ops->clear(cx, obj);
}
JS_PUBLIC_API(JSIdArray *)

View File

@ -523,6 +523,22 @@ JS_LockGCThing(JSContext *cx, void *thing);
extern JS_PUBLIC_API(JSBool)
JS_UnlockGCThing(JSContext *cx, 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.
*/
extern JS_PUBLIC_API(void)
JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg);
extern JS_PUBLIC_API(void)
JS_GC(JSContext *cx);
@ -561,16 +577,17 @@ struct JSClass {
JSNative construct;
JSXDRObjectOp xdrObject;
JSHasInstanceOp hasInstance;
jsword spare[2];
JSMarkOp mark;
jsword spare;
};
#define JSCLASS_HAS_PRIVATE 0x01 /* class instances have private slot */
#define JSCLASS_NEW_ENUMERATE 0x02 /* class has JSNewEnumerateOp method */
#define JSCLASS_NEW_RESOLVE 0x04 /* class has JSNewResolveOp method */
#define JSCLASS_PRIVATE_IS_NSISUPPORTS 0x08 /* private slot is nsISupports* */
/* Fill in null values for unused members. */
#define JSCLASS_NO_OPTIONAL_MEMBERS \
0,0,0,0,0,0,{0,0}
#define JSCLASS_PRIVATE_IS_NSISUPPORTS 0x08 /* private is (nsISupports *) */
/* Initializer for unused members of statically initialized JSClass structs. */
#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,0
struct JSObjectOps {
/* Mandatory non-null function pointer members. */
@ -596,10 +613,10 @@ struct JSObjectOps {
JSHasInstanceOp hasInstance;
JSSetObjectSlotOp setProto;
JSSetObjectSlotOp setParent;
JSMarkOp mark;
JSFinalizeOp clear;
jsword spare1;
jsword spare2;
jsword spare3;
jsword spare4;
};
/*

View File

@ -306,8 +306,8 @@ js_FreeAtomState(JSContext *cx, JSAtomState *state)
}
typedef struct MarkArgs {
JSRuntime *runtime;
JSGCThingMarker mark;
void *data;
} MarkArgs;
JS_STATIC_DLL_CALLBACK(intN)
@ -323,19 +323,19 @@ js_atom_marker(JSHashEntry *he, intN i, void *arg)
key = ATOM_KEY(atom);
if (JSVAL_IS_GCTHING(key)) {
args = (MarkArgs *) arg;
args->mark(args->runtime, JSVAL_TO_GCTHING(key));
args->mark(JSVAL_TO_GCTHING(key), args->data);
}
}
return HT_ENUMERATE_NEXT;
}
void
js_MarkAtomState(JSAtomState *state, JSGCThingMarker mark)
js_MarkAtomState(JSAtomState *state, JSGCThingMarker mark, void *data)
{
MarkArgs args;
args.runtime = state->runtime;
args.mark = mark;
args.data = data;
JS_HashTableEnumerateEntries(state->table, js_atom_marker, &args);
}

View File

@ -241,10 +241,10 @@ js_FreeAtomState(JSContext *cx, JSAtomState *state);
* Atom garbage collection hooks.
*/
typedef void
(*JSGCThingMarker)(JSRuntime *rt, void *thing);
(*JSGCThingMarker)(void *thing, void *data);
extern void
js_MarkAtomState(JSAtomState *state, JSGCThingMarker mark);
js_MarkAtomState(JSAtomState *state, JSGCThingMarker mark, void *data);
extern void
js_SweepAtomState(JSAtomState *state, uintN gcflags);

View File

@ -68,7 +68,7 @@ static JSClass ExceptionClass = {
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, exn_finalize,
NULL, NULL, NULL, Exception,
0,0,{0,0}
NULL, NULL, NULL, 0
};
/*

View File

@ -1043,6 +1043,21 @@ fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
#endif /* !JS_HAS_INSTANCEOF */
static uint32
fun_mark(JSContext *cx, JSObject *obj, void *arg)
{
JSFunction *fun;
fun = (JSFunction *) JS_GetPrivate(cx, obj);
if (fun) {
if (fun->atom)
js_MarkAtom(cx, fun->atom, arg);
if (fun->script)
js_MarkScript(cx, fun->script, arg);
}
return 0;
}
JSClass js_FunctionClass = {
js_Function_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
@ -1053,7 +1068,7 @@ JSClass js_FunctionClass = {
NULL, NULL,
NULL, NULL,
fun_xdrObject, fun_hasInstance,
{0,0}
fun_mark, 0
};
static JSBool

View File

@ -53,7 +53,6 @@
#include "jsatom.h"
#include "jscntxt.h"
#include "jsconfig.h"
#include "jsfun.h"
#include "jsgc.h"
#include "jsinterp.h"
#include "jslock.h"
@ -204,6 +203,7 @@ js_AllocGCThing(JSContext *cx, uintN flags)
rt = cx->runtime;
JS_LOCK_GC(rt);
JS_ASSERT(rt->gcLevel == 0);
METER(rt->gcStats.alloc++);
retry:
thing = rt->gcFreeList;
@ -413,15 +413,6 @@ js_UnlockGCThing(JSContext *cx, void *thing)
JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
JS_EXPORT_DATA(void *) js_LiveThingToFind;
typedef struct GCMarkNode GCMarkNode;
struct GCMarkNode {
void *thing;
char *name;
GCMarkNode *next;
GCMarkNode *prev;
};
#ifdef HAVE_XPCONNECT
#include "dump_xpc.h"
#endif
@ -500,50 +491,21 @@ gc_dump_thing(JSRuntime* rt, JSGCThing *thing, uint8 flags, GCMarkNode *prev,
free(path);
}
static void
gc_mark_node(JSRuntime *rt, void *thing, GCMarkNode *prev);
#define GC_MARK(_rt, _thing, _name, _prev) \
JS_BEGIN_MACRO \
GCMarkNode _node; \
_node.thing = _thing; \
_node.name = _name; \
_node.next = NULL; \
_node.prev = _prev; \
if (_prev) ((GCMarkNode *)(_prev))->next = &_node; \
gc_mark_node(_rt, _thing, &_node); \
JS_END_MACRO
static void
gc_mark(JSRuntime *rt, void *thing)
{
GC_MARK(rt, thing, "atom", NULL);
}
#define GC_MARK_ATOM(rt, atom, prev) gc_mark_atom(rt, atom, prev)
#define GC_MARK_SCRIPT(rt, script, prev) gc_mark_script(rt, script, prev)
#else /* !GC_MARK_DEBUG */
#define GC_MARK(rt, thing, name, prev) gc_mark(rt, thing)
#define GC_MARK_ATOM(rt, atom, prev) gc_mark_atom(rt, atom)
#define GC_MARK_SCRIPT(rt, script, prev) gc_mark_script(rt, script)
static void
gc_mark(JSRuntime *rt, void *thing);
#endif /* !GC_MARK_DEBUG */
static void
gc_mark_atom(JSRuntime *rt, JSAtom *atom
#ifdef GC_MARK_DEBUG
, GCMarkNode *prev
#endif
)
gc_mark_atom_key_thing(void *thing, void *arg)
{
JSContext *cx = (JSContext *) arg;
GC_MARK(cx, thing, "atom", NULL);
}
void
js_MarkAtom(JSContext *cx, JSAtom *atom, void *arg)
{
jsval key;
if (!atom || atom->flags & ATOM_MARK)
if (atom->flags & ATOM_MARK)
return;
atom->flags |= ATOM_MARK;
key = ATOM_KEY(atom);
@ -558,47 +520,26 @@ gc_mark_atom(JSRuntime *rt, JSAtom *atom
JS_snprintf(name, sizeof name, "<%x>", key);
}
#endif
GC_MARK(rt, JSVAL_TO_GCTHING(key), name, prev);
GC_MARK(cx, JSVAL_TO_GCTHING(key), name, arg);
}
}
static void
gc_mark_script(JSRuntime *rt, JSScript *script
#ifdef GC_MARK_DEBUG
, GCMarkNode *prev
#endif
)
{
JSAtomMap *map;
uintN i, length;
JSAtom **vector;
map = &script->atomMap;
length = map->length;
vector = map->vector;
for (i = 0; i < length; i++)
GC_MARK_ATOM(rt, vector[i], prev);
}
static void
#ifdef GC_MARK_DEBUG
gc_mark_node(JSRuntime *rt, void *thing, GCMarkNode *prev)
#else
gc_mark(JSRuntime *rt, void *thing)
#endif
void
js_MarkGCThing(JSContext *cx, void *thing, void *arg)
{
JSRuntime *rt;
uint8 flags, *flagp;
JSObject *obj;
uint32 nslots;
jsval v, *vp, *end;
#ifdef GC_MARK_DEBUG
JSScope *scope;
JSClass *clasp;
JSScript *script;
JSFunction *fun;
JSScopeProperty *sprop;
JSSymbol *sym;
#endif
if (!thing)
return;
rt = cx->runtime;
flagp = gc_find_flags(rt, thing);
if (!flagp)
return;
@ -627,134 +568,65 @@ gc_mark(JSRuntime *rt, void *thing)
if ((flags & GCF_TYPEMASK) == GCX_OBJECT) {
obj = (JSObject *) thing;
vp = obj->slots;
if (vp) {
scope = OBJ_IS_NATIVE(obj) ? OBJ_SCOPE(obj) : NULL;
if (scope) {
clasp = (JSClass *) JSVAL_TO_PRIVATE(obj->slots[JSSLOT_CLASS]);
if (clasp == &js_ScriptClass) {
v = vp[JSSLOT_PRIVATE];
if (!JSVAL_IS_VOID(v)) {
script = (JSScript *) JSVAL_TO_PRIVATE(v);
if (script)
GC_MARK_SCRIPT(rt, script, prev);
}
}
if (clasp == &js_FunctionClass) {
v = vp[JSSLOT_PRIVATE];
if (!JSVAL_IS_VOID(v)) {
fun = (JSFunction *) JSVAL_TO_PRIVATE(v);
if (fun) {
if (fun->atom)
GC_MARK_ATOM(rt, fun->atom, prev);
if (fun->script)
GC_MARK_SCRIPT(rt, fun->script, prev);
}
}
}
for (sprop = scope->props; sprop; sprop = sprop->next) {
for (sym = sprop->symbols; sym; sym = sym->next) {
if (JSVAL_IS_INT(sym_id(sym)))
continue;
GC_MARK_ATOM(rt, sym_atom(sym), prev);
}
#if JS_HAS_GETTER_SETTER
if (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
nslots = (obj->map->ops->mark)
? obj->map->ops->mark(cx, obj, arg)
: obj->map->freeslot;
#ifdef GC_MARK_DEBUG
char buf[64];
JSAtom *atom = sym_atom(sprop->symbols);
const char *id = (atom && ATOM_IS_STRING(atom))
? JS_GetStringBytes(ATOM_TO_STRING(atom))
: "unknown";
scope = OBJ_IS_NATIVE(obj) ? OBJ_SCOPE(obj) : NULL;
#endif
if (sprop->attrs & JSPROP_GETTER) {
for (end = vp + nslots; vp < end; vp++) {
v = *vp;
if (JSVAL_IS_GCTHING(v)) {
#ifdef GC_MARK_DEBUG
JS_snprintf(buf, sizeof buf, "%s %s",
id, js_getter_str);
#endif
GC_MARK(rt,
JSVAL_TO_GCTHING((jsval)
SPROP_GETTER_SCOPE(sprop, scope)),
buf,
prev);
char name[32];
if (scope) {
uint32 slot;
jsval nval;
slot = vp - obj->slots;
for (sprop = scope->props; ; sprop = sprop->next) {
if (!sprop) {
switch (slot) {
case JSSLOT_PROTO:
strcpy(name, "__proto__");
break;
case JSSLOT_PARENT:
strcpy(name, "__parent__");
break;
case JSSLOT_PRIVATE:
strcpy(name, "__private__");
break;
default:
JS_snprintf(name, sizeof name,
"**UNKNOWN SLOT %ld**",
(long)slot);
break;
}
break;
}
if (sprop->attrs & JSPROP_SETTER) {
#ifdef GC_MARK_DEBUG
JS_snprintf(buf, sizeof buf, "%s %s",
id, js_setter_str);
#endif
GC_MARK(rt,
JSVAL_TO_GCTHING((jsval)
SPROP_SETTER_SCOPE(sprop, scope)),
buf,
prev);
if (sprop->slot == slot) {
nval = sprop->symbols
? js_IdToValue(sym_id(sprop->symbols))
: sprop->id;
if (JSVAL_IS_INT(nval)) {
JS_snprintf(name, sizeof name, "%ld",
(long)JSVAL_TO_INT(nval));
} else if (JSVAL_IS_STRING(nval)) {
JS_snprintf(name, sizeof name, "%s",
JS_GetStringBytes(JSVAL_TO_STRING(nval)));
} else {
strcpy(name, "**FINALIZED ATOM KEY**");
}
break;
}
}
#endif /* JS_HAS_GETTER_SETTER */
}
}
if (!scope || scope->object == obj)
end = vp + obj->map->freeslot;
else
end = vp + JS_INITIAL_NSLOTS;
for (; vp < end; vp++) {
v = *vp;
if (JSVAL_IS_GCTHING(v)) {
#ifdef GC_MARK_DEBUG
char name[32];
if (scope) {
uint32 slot;
jsval nval;
slot = vp - obj->slots;
for (sprop = scope->props; ; sprop = sprop->next) {
if (!sprop) {
switch (slot) {
case JSSLOT_PROTO:
strcpy(name, "__proto__");
break;
case JSSLOT_PARENT:
strcpy(name, "__parent__");
break;
case JSSLOT_PRIVATE:
strcpy(name, "__private__");
break;
default:
JS_snprintf(name, sizeof name,
"**UNKNOWN SLOT %ld**",
(long)slot);
break;
}
break;
}
if (sprop->slot == slot) {
nval = sprop->symbols
? js_IdToValue(sym_id(sprop->symbols))
: sprop->id;
if (JSVAL_IS_INT(nval)) {
JS_snprintf(name, sizeof name, "%ld",
(long)JSVAL_TO_INT(nval));
} else if (JSVAL_IS_STRING(nval)) {
JS_snprintf(name, sizeof name, "%s",
JS_GetStringBytes(JSVAL_TO_STRING(nval)));
} else {
strcpy(name, "**FINALIZED ATOM KEY**");
}
break;
}
}
}
}
#endif
GC_MARK(rt, JSVAL_TO_GCTHING(v), name, prev);
}
}
}
GC_MARK(cx, JSVAL_TO_GCTHING(v), name, arg);
}
}
}
METER(rt->gcStats.depth--);
}
@ -774,13 +646,13 @@ gc_root_marker(JSHashEntry *he, intN i, void *arg)
/* Ignore null object and scalar values. */
if (!JSVAL_IS_NULL(v) && JSVAL_IS_GCTHING(v)) {
JSRuntime *rt = (JSRuntime *)arg;
JSContext *cx = (JSContext *)arg;
#ifdef DEBUG
JSArena *a;
JSBool root_points_to_gcArenaPool = JS_FALSE;
void *thing = JSVAL_TO_GCTHING(v);
for (a = rt->gcArenaPool.first.next; a; a = a->next) {
for (a = cx->runtime->gcArenaPool.first.next; a; a = a->next) {
if (JS_UPTRDIFF(thing, a->base) < a->avail - a->base) {
root_points_to_gcArenaPool = JS_TRUE;
break;
@ -796,7 +668,7 @@ gc_root_marker(JSHashEntry *he, intN i, void *arg)
JS_ASSERT(root_points_to_gcArenaPool);
#endif
GC_MARK(rt, JSVAL_TO_GCTHING(v), he->value ? he->value : "root", NULL);
GC_MARK(cx, JSVAL_TO_GCTHING(v), he->value ? he->value : "root", NULL);
}
return HT_ENUMERATE_NEXT;
}
@ -805,9 +677,9 @@ JS_STATIC_DLL_CALLBACK(intN)
gc_lock_marker(JSHashEntry *he, intN i, void *arg)
{
void *thing = (void *)he->key;
JSRuntime *rt = (JSRuntime *)arg;
JSContext *cx = (JSContext *)arg;
GC_MARK(rt, thing, "locked object", NULL);
GC_MARK(cx, thing, "locked object", NULL);
return HT_ENUMERATE_NEXT;
}
@ -961,10 +833,10 @@ restart:
/*
* Mark phase.
*/
JS_HashTableEnumerateEntries(rt->gcRootsHash, gc_root_marker, rt);
JS_HashTableEnumerateEntries(rt->gcRootsHash, gc_root_marker, cx);
if (rt->gcLocksHash)
JS_HashTableEnumerateEntries(rt->gcLocksHash, gc_lock_marker, rt);
js_MarkAtomState(&rt->atomState, gc_mark);
JS_HashTableEnumerateEntries(rt->gcLocksHash, gc_lock_marker, cx);
js_MarkAtomState(&rt->atomState, gc_mark_atom_key_thing, cx);
iter = NULL;
while ((acx = js_ContextIterator(rt, &iter)) != NULL) {
/*
@ -1010,25 +882,25 @@ restart:
for (vp = (jsval *)begin; vp < (jsval *)end; vp++) {
v = *vp;
if (JSVAL_IS_GCTHING(v))
GC_MARK(rt, JSVAL_TO_GCTHING(v), "stack", NULL);
GC_MARK(cx, JSVAL_TO_GCTHING(v), "stack", NULL);
}
if (end == (jsuword)sp)
break;
}
}
do {
GC_MARK(rt, fp->scopeChain, "scope chain", NULL);
GC_MARK(rt, fp->thisp, "this", NULL);
GC_MARK(cx, fp->scopeChain, "scope chain", NULL);
GC_MARK(cx, fp->thisp, "this", NULL);
if (JSVAL_IS_GCTHING(fp->rval))
GC_MARK(rt, JSVAL_TO_GCTHING(fp->rval), "rval", NULL);
GC_MARK(cx, JSVAL_TO_GCTHING(fp->rval), "rval", NULL);
if (fp->callobj)
GC_MARK(rt, fp->callobj, "call object", NULL);
GC_MARK(cx, fp->callobj, "call object", NULL);
if (fp->argsobj)
GC_MARK(rt, fp->argsobj, "arguments object", NULL);
GC_MARK(cx, fp->argsobj, "arguments object", NULL);
if (fp->script)
GC_MARK_SCRIPT(rt, fp->script, NULL);
js_MarkScript(cx, fp->script, NULL);
if (fp->sharpArray)
GC_MARK(rt, fp->sharpArray, "sharp array", NULL);
GC_MARK(cx, fp->sharpArray, "sharp array", NULL);
} while ((fp = fp->down) != NULL);
}
@ -1037,13 +909,13 @@ restart:
acx->fp->dormantNext = NULL;
/* Mark other roots-by-definition in acx. */
GC_MARK(rt, acx->globalObject, "global object", NULL);
GC_MARK(rt, acx->newborn[GCX_OBJECT], "newborn object", NULL);
GC_MARK(rt, acx->newborn[GCX_STRING], "newborn string", NULL);
GC_MARK(rt, acx->newborn[GCX_DOUBLE], "newborn double", NULL);
GC_MARK(cx, acx->globalObject, "global object", NULL);
GC_MARK(cx, acx->newborn[GCX_OBJECT], "newborn object", NULL);
GC_MARK(cx, acx->newborn[GCX_STRING], "newborn string", NULL);
GC_MARK(cx, acx->newborn[GCX_DOUBLE], "newborn double", NULL);
#if JS_HAS_EXCEPTIONS
if (acx->throwing && JSVAL_IS_GCTHING(acx->exception))
GC_MARK(rt, JSVAL_TO_GCTHING(acx->exception), "exception", NULL);
GC_MARK(cx, JSVAL_TO_GCTHING(acx->exception), "exception", NULL);
#endif
}

View File

@ -18,7 +18,7 @@
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
@ -37,24 +37,25 @@
/*
* JS Garbage Collector.
*/
#include "jsprvtd.h"
#include "jspubtd.h"
JS_BEGIN_EXTERN_C
/* GC thing type indexes. */
#define GCX_OBJECT 0 /* JSObject */
#define GCX_STRING 1 /* JSString */
#define GCX_DOUBLE 2 /* jsdouble */
#define GCX_OBJECT 0 /* JSObject */
#define GCX_STRING 1 /* JSString */
#define GCX_DOUBLE 2 /* jsdouble */
#define GCX_DECIMAL 3 /* JSDecimal */
#define GCX_NTYPES 4
/* GC flag definitions (type index goes in low bits). */
#define GCF_TYPEMASK JS_BITMASK(2) /* use low bits for type */
#define GCF_MARK JS_BIT(2) /* mark bit */
#define GCF_FINAL JS_BIT(3) /* in finalization bit */
#define GCF_LOCKBIT 4 /* lock bit shift and mask */
#define GCF_LOCKMASK (JS_BITMASK(4) << GCF_LOCKBIT)
#define GCF_LOCK JS_BIT(GCF_LOCKBIT) /* lock request bit in API */
#define GCF_TYPEMASK JS_BITMASK(2) /* use low bits for type */
#define GCF_MARK JS_BIT(2) /* mark bit */
#define GCF_FINAL JS_BIT(3) /* in finalization bit */
#define GCF_LOCKBIT 4 /* lock bit shift and mask */
#define GCF_LOCKMASK (JS_BITMASK(4) << GCF_LOCKBIT)
#define GCF_LOCK JS_BIT(GCF_LOCKBIT) /* lock request bit in API */
#if 1
/*
@ -87,6 +88,40 @@ js_LockGCThing(JSContext *cx, void *thing);
extern JSBool
js_UnlockGCThing(JSContext *cx, void *thing);
extern void
js_MarkAtom(JSContext *cx, JSAtom *atom, void *arg);
extern void
js_MarkGCThing(JSContext *cx, void *thing, void *arg);
#ifdef GC_MARK_DEBUG
typedef struct GCMarkNode GCMarkNode;
struct GCMarkNode {
void *thing;
const char *name;
GCMarkNode *next;
GCMarkNode *prev;
};
#define GC_MARK(_cx, _thing, _name, _prev) \
JS_BEGIN_MACRO \
GCMarkNode _node; \
_node.thing = _thing; \
_node.name = _name; \
_node.next = NULL; \
_node.prev = _prev; \
if (_prev) ((GCMarkNode *)(_prev))->next = &_node; \
js_MarkGCThing(_cx, _thing, &_node); \
JS_END_MACRO
#else /* !GC_MARK_DEBUG */
#define GC_MARK(cx, thing, name, prev) js_MarkGCThing(cx, thing, NULL)
#endif /* !GC_MARK_DEBUG */
extern JS_FRIEND_API(void)
js_ForceGC(JSContext *cx);

View File

@ -91,7 +91,8 @@ JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
js_Call, js_Construct,
NULL, js_HasInstance,
js_SetProtoOrParent, js_SetProtoOrParent,
0,0,0,0
js_Mark, js_Clear,
0, 0
};
#ifdef XP_MAC
@ -1268,7 +1269,8 @@ JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
NULL, NULL,
NULL, NULL,
js_SetProtoOrParent, js_SetProtoOrParent,
0,0,0,0
js_Mark, js_Clear,
0, 0
};
static JSObjectOps *
@ -1283,7 +1285,7 @@ JSClass js_WithClass = {
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
with_getObjectOps,
0,0,0,0,0,{0,0}
0,0,0,0,0,0,0
};
#if JS_HAS_OBJ_PROTO_PROP
@ -3010,6 +3012,85 @@ out:
#endif /* JS_HAS_XDR */
uint32
js_Mark(JSContext *cx, JSObject *obj, void *arg)
{
JSScope *scope;
JSScopeProperty *sprop;
JSSymbol *sym;
JSClass *clasp;
JS_ASSERT(OBJ_IS_NATIVE(obj));
scope = OBJ_SCOPE(obj);
for (sprop = scope->props; sprop; sprop = sprop->next) {
for (sym = sprop->symbols; sym; sym = sym->next) {
if (JSVAL_IS_INT(sym_id(sym)))
continue;
js_MarkAtom(cx, sym_atom(sym), arg);
}
#if JS_HAS_GETTER_SETTER
if (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
#ifdef GC_MARK_DEBUG
char buf[64];
JSAtom *atom = sym_atom(sprop->symbols);
const char *id = (atom && ATOM_IS_STRING(atom))
? JS_GetStringBytes(ATOM_TO_STRING(atom))
: "unknown";
#endif
if (sprop->attrs & JSPROP_GETTER) {
#ifdef GC_MARK_DEBUG
JS_snprintf(buf, sizeof buf, "%s %s",
id, js_getter_str);
#endif
GC_MARK(cx,
JSVAL_TO_GCTHING((jsval)
SPROP_GETTER_SCOPE(sprop, scope)),
buf,
arg);
}
if (sprop->attrs & JSPROP_SETTER) {
#ifdef GC_MARK_DEBUG
JS_snprintf(buf, sizeof buf, "%s %s",
id, js_setter_str);
#endif
GC_MARK(cx,
JSVAL_TO_GCTHING((jsval)
SPROP_SETTER_SCOPE(sprop, scope)),
buf,
arg);
}
}
#endif /* JS_HAS_GETTER_SETTER */
}
/* 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, arg);
return (scope->object == obj) ? obj->map->freeslot : JS_INITIAL_NSLOTS;
}
void
js_Clear(JSContext *cx, JSObject *obj)
{
JSScope *scope;
uint32 i, n;
/* Clear our scope of all symbols and properties. */
JS_LOCK_OBJ(cx, obj);
scope = OBJ_SCOPE(obj);
scope->ops->clear(cx, scope);
/* Clear slot values and reset freeslot so we're consistent. */
i = scope->map.nslots;
n = JSSLOT_FREE(LOCKED_OBJ_GET_CLASS(obj));
while (--i >= n)
obj->slots[i] = JSVAL_VOID;
scope->map.freeslot = n;
JS_UNLOCK_OBJ(cx, obj);
}
#ifdef DEBUG

View File

@ -354,6 +354,12 @@ 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_Clear(JSContext *cx, JSObject *obj);
JS_END_EXTERN_C
#endif /* jsobj_h___ */

View File

@ -188,6 +188,9 @@ typedef JSBool
(* CRT_CALL JSSetObjectSlotOp)(JSContext *cx, JSObject *obj, uint32 slot,
JSObject *pobj);
typedef uint32
(* CRT_CALL JSMarkOp)(JSContext *cx, JSObject *obj, void *arg);
/* JSObjectOps function pointer typedefs. */
typedef JSObjectMap *

View File

@ -2488,8 +2488,7 @@ JSClass js_RegExpClass = {
JS_PropertyStub, JS_PropertyStub, regexp_getProperty, regexp_setProperty,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, regexp_finalize,
NULL, NULL, regexp_call, NULL,
regexp_xdrObject,
0,{0,0}
regexp_xdrObject, NULL, NULL, 0
};
static JSBool

View File

@ -622,13 +622,24 @@ script_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
#endif
}
static uint32
script_mark(JSContext *cx, JSObject *obj, void *arg)
{
JSScript *script;
script = (JSScript *) JS_GetPrivate(cx, obj);
if (script)
js_MarkScript(cx, script, arg);
return 0;
}
JS_FRIEND_DATA(JSClass) js_ScriptClass = {
js_Script_str,
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, script_finalize,
NULL, NULL, script_call, NULL,/*XXXbe xdr*/
0,0,{0,0}
NULL, NULL, script_mark, 0
};
#if JS_HAS_SCRIPT_OBJECT
@ -783,6 +794,20 @@ js_DestroyScript(JSContext *cx, JSScript *script)
JS_free(cx, script);
}
void
js_MarkScript(JSContext *cx, JSScript *script, void *arg)
{
JSAtomMap *map;
uintN i, length;
JSAtom **vector;
map = &script->atomMap;
length = map->length;
vector = map->vector;
for (i = 0; i < length; i++)
js_MarkAtom(cx, vector[i], arg);
}
jssrcnote *
js_GetSrcNote(JSScript *script, jsbytecode *pc)
{

View File

@ -70,6 +70,20 @@ struct JSScript {
JSObject *object; /* optional Script-class object wrapper */
};
#define JSSCRIPT_FIND_CATCH_START(script, pc, catchpc) \
JS_BEGIN_MACRO \
JSTryNote *_tn = (script)->trynotes; \
jsbytecode *_catchpc = NULL; \
if (_tn) { \
ptrdiff_t _offset = PTRDIFF(pc, (script)->main, jsbytecode); \
while (JS_UPTRDIFF(_offset, _tn->start) >= (jsuword)_tn->length) \
_tn++; \
if (_tn->catchStart) \
_catchpc = (script)->main + _tn->catchStart; \
} \
catchpc = _catchpc; \
JS_END_MACRO
extern JS_FRIEND_DATA(JSClass) js_ScriptClass;
extern JSObject *
@ -91,6 +105,9 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun);
extern void
js_DestroyScript(JSContext *cx, JSScript *script);
extern void
js_MarkScript(JSContext *cx, JSScript *script, void *arg);
extern jssrcnote *
js_GetSrcNote(JSScript *script, jsbytecode *pc);

View File

@ -424,7 +424,9 @@ JSObjectOps JavaArray_ops = {
NULL, /* hasInstance */
NULL, /* setProto */
NULL, /* setParent */
0,0,0,0 /* spare */
NULL, /* mark */
NULL, /* clear */
0,0 /* spare */
};
static JSObjectOps *
@ -445,7 +447,8 @@ JSClass JavaArray_class = {
NULL,
NULL,
NULL,
{0, 0},
NULL,
0,
};
extern JS_IMPORT_DATA(JSObjectOps) js_ObjectOps;

View File

@ -561,7 +561,9 @@ JSObjectOps JavaClass_ops = {
JavaClass_hasInstance, /* hasInstance */
NULL, /* setProto */
NULL, /* setParent */
0,0,0,0 /* spare */
NULL, /* mark */
NULL, /* clear */
0,0 /* spare */
};
static JSObjectOps *
@ -582,7 +584,8 @@ JSClass JavaClass_class = {
NULL,
NULL,
NULL,
{0, 0},
NULL,
0,
};
static JSObject *

View File

@ -165,7 +165,8 @@ JSClass JavaMember_class = {
NULL, /* construct */
NULL, /* xdrObject */
NULL, /* hasInstance */
{0, 0}, /* spare */
NULL, /* mark */
0, /* spare */
};
JSBool

View File

@ -908,7 +908,9 @@ JSObjectOps JavaObject_ops = {
NULL, /* hasInstance */
NULL, /* setProto */
NULL, /* setParent */
0,0,0,0 /* spare */
NULL, /* mark */
NULL, /* clear */
0,0 /* spare */
};
static JSObjectOps *
@ -929,7 +931,8 @@ JSClass JavaObject_class = {
NULL, /* construct */
NULL, /* xdrObject */
NULL, /* hasInstance */
{0, 0}, /* spare */
NULL, /* mark */
0, /* spare */
};
extern JS_IMPORT_DATA(JSObjectOps) js_ObjectOps;

View File

@ -336,7 +336,8 @@ JSClass JavaPackage_class = {
NULL, /* construct */
NULL, /* xdrObject */
NULL, /* hasInstance */
{0, 0}, /* spare */
NULL, /* mark */
0, /* spare */
};
JavaPackageDef

View File

@ -824,13 +824,15 @@ static JSObjectOps WrappedNative_ops = {
WrappedNative_HasInstance, /* hasInstance */
nsnull, /* setProto */
nsnull, /* setParent */
0,0,0,0 /* spare */
nsnull, /* filled in at runtime! - mark */
nsnull, /* filled in at runtime! - clear */
0,0 /* spare */
};
static JSObjectOps WrappedNativeWithCall_ops = {
/* Mandatory non-null function pointer members. */
nsnull, /* filled in at runtime! - newObjectMap */
nsnull, /* filled in at runtime! - destroyObjectMap */
nsnull, /* filled in at runtime! - newObjectMap */
nsnull, /* filled in at runtime! - destroyObjectMap */
WrappedNative_LookupProperty,
WrappedNative_DefineProperty,
WrappedNative_GetProperty,
@ -849,9 +851,11 @@ static JSObjectOps WrappedNativeWithCall_ops = {
WrappedNative_Construct, /* construct */
nsnull, /* xdrObject */
WrappedNative_HasInstance, /* hasInstance */
NULL, /* setProto */
NULL, /* setParent */
0,0,0,0 /* spare */
nsnull, /* setProto */
nsnull, /* setParent */
nsnull, /* filled in at runtime! - mark */
nsnull, /* filled in at runtime! - clear */
0,0 /* spare */
};
JS_STATIC_DLL_CALLBACK(JSObjectOps *)
@ -905,9 +909,13 @@ JSBool xpc_InitWrappedNativeJSOps()
{
WrappedNative_ops.newObjectMap = js_ObjectOps.newObjectMap;
WrappedNative_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
WrappedNative_ops.mark = js_ObjectOps.mark;
WrappedNative_ops.clear = js_ObjectOps.clear;
WrappedNativeWithCall_ops.newObjectMap = js_ObjectOps.newObjectMap;
WrappedNativeWithCall_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
WrappedNativeWithCall_ops.mark = js_ObjectOps.mark;
WrappedNativeWithCall_ops.clear = js_ObjectOps.clear;
}
return JS_TRUE;
}