diff --git a/js/src/jsfun.c b/js/src/jsfun.c index d7747324ad9..1c5cff66f5b 100644 --- a/js/src/jsfun.c +++ b/js/src/jsfun.c @@ -969,6 +969,28 @@ static JSPropertySpec function_props[] = { {0,0,0,0,0} }; +void +js_MarkFunction(JSContext *cx, JSFunction *fun) +{ + if (fun->object) + GC_MARK(cx, fun->object, "object"); + if (fun->atom) + GC_MARK_ATOM(cx, fun->atom); + if (FUN_INTERPRETED(fun) && fun->u.i.script) + js_MarkScript(cx, fun->u.i.script); +} + +void +js_FinalizeFunction(JSContext *cx, JSFunction *fun) +{ + /* + * Null-check of i.script is required since the parser sets interpreted + * very early. + */ + if (FUN_INTERPRETED(fun) && fun->u.i.script) + js_DestroyScript(cx, fun->u.i.script); +} + static JSBool fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { @@ -1181,36 +1203,6 @@ fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) } } -static void -fun_finalize(JSContext *cx, JSObject *obj) -{ - JSFunction *fun; - JSScript *script; - - /* No valid function object should lack private data, but check anyway. */ - fun = (JSFunction *) JS_GetPrivate(cx, obj); - if (!fun) - return; - - if (fun->object == obj) - fun->object = NULL; - - /* - * Null-check of i.script is required since the parser sets interpreted - * very early. - * - * Here js_IsAboutToBeFinalized works because obj is finalized before - * JSFunction. See comments in js_GC before the finalization loop. - */ - if (FUN_INTERPRETED(fun) && fun->u.i.script && - js_IsAboutToBeFinalized(cx, fun)) - { - script = fun->u.i.script; - fun->u.i.script = NULL; - js_DestroyScript(cx, script); - } -} - #if JS_HAS_XDR #include "jsxdrapi.h" @@ -1444,13 +1436,8 @@ fun_mark(JSContext *cx, JSObject *obj, void *arg) JSFunction *fun; fun = (JSFunction *) JS_GetPrivate(cx, obj); - if (fun) { + if (fun) GC_MARK(cx, fun, "private"); - if (fun->atom) - GC_MARK_ATOM(cx, fun->atom); - if (FUN_INTERPRETED(fun) && fun->u.i.script) - js_MarkScript(cx, fun->u.i.script); - } return 0; } @@ -1475,7 +1462,7 @@ JS_FRIEND_DATA(JSClass) js_FunctionClass = { JS_PropertyStub, JS_PropertyStub, fun_getProperty, JS_PropertyStub, fun_enumerate, (JSResolveOp)fun_resolve, - fun_convert, fun_finalize, + fun_convert, JS_FinalizeStub, NULL, NULL, NULL, NULL, fun_xdrObject, fun_hasInstance, @@ -2125,10 +2112,10 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(funobj), &tvr); /* - * Allocate fun after allocating funobj so slot allocation in js_NewObject - * does not wipe out fun from newborn[GCX_PRIVATE]. + * Allocate fun after allocating funobj so allocations in js_NewObject + * and hooks called from it do not wipe out fun from newborn[GCX_FUNCTION]. */ - fun = (JSFunction *) js_NewGCThing(cx, GCX_PRIVATE, sizeof(JSFunction)); + fun = (JSFunction *) js_NewGCThing(cx, GCX_FUNCTION, sizeof(JSFunction)); if (!fun) goto out; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 0055d7d2e1a..93cea17b672 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -86,6 +86,12 @@ extern JS_FRIEND_DATA(JSClass) js_FunctionClass; (!JSVAL_IS_PRIMITIVE(v) && \ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass) +extern void +js_MarkFunction(JSContext *cx, JSFunction *fun); + +extern void +js_FinalizeFunction(JSContext *cx, JSFunction *fun); + extern JSBool js_fun_toString(JSContext *cx, JSObject *obj, uint32 indent, uintN argc, jsval *argv, jsval *rval); diff --git a/js/src/jsgc.c b/js/src/jsgc.c index 67272da9e34..df5a5d3d8c8 100644 --- a/js/src/jsgc.c +++ b/js/src/jsgc.c @@ -242,14 +242,6 @@ JS_STATIC_ASSERT(sizeof(JSGCThing) >= sizeof(jsdouble)); /* We want to use all the available GC thing space for object's slots. */ JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(JSGCThing) == 0); -/* - * Ensure that GC-allocated JSFunction and JSObject would go to different - * lists so we can easily finalize JSObject before JSFunction. See comments - * in js_GC. - */ -JS_STATIC_ASSERT(GC_FREELIST_INDEX(sizeof(JSFunction)) != - GC_FREELIST_INDEX(sizeof(JSObject))); - /* * JSPtrTable capacity growth descriptor. The table grows by powers of two * starting from capacity JSPtrTableInfo.minCapacity, but switching to linear @@ -540,7 +532,7 @@ static GCFinalizeOp gc_finalizers[GCX_NTYPES] = { (GCFinalizeOp) js_FinalizeString, /* GCX_STRING */ (GCFinalizeOp) js_FinalizeDouble, /* GCX_DOUBLE */ (GCFinalizeOp) js_FinalizeString, /* GCX_MUTABLE_STRING */ - NULL, /* GCX_PRIVATE */ + (GCFinalizeOp) js_FinalizeFunction, /* GCX_FUNCTION */ (GCFinalizeOp) js_FinalizeXMLNamespace, /* GCX_NAMESPACE */ (GCFinalizeOp) js_FinalizeXMLQName, /* GCX_QNAME */ (GCFinalizeOp) js_FinalizeXML, /* GCX_XML */ @@ -1922,6 +1914,17 @@ gc_dump_thing(JSContext *cx, JSGCThing *thing, FILE *fp) fprintf(fp, "object %8p %s", privateThing, className); break; } + case GCX_FUNCTION: + { + JSFunction *fun = (JSFunction *)thing; + + fprintf(fp, "function"); + if (fun->atom && ATOM_IS_STRING(fun->atom)) { + fputc(' ', fp); + js_FileEscapedString(fp, ATOM_TO_STRING(fun->atom), 0); + } + break; + } #if JS_HAS_XML_SUPPORT case GCX_NAMESPACE: { @@ -1958,9 +1961,6 @@ gc_dump_thing(JSContext *cx, JSGCThing *thing, FILE *fp) case GCX_DOUBLE: fprintf(fp, "double %g", *(jsdouble *)thing); break; - case GCX_PRIVATE: - fprintf(fp, "private %8p", (void *)thing); - break; default: fputs("string ", fp); js_FileEscapedString(fp, (JSString *)thing, 0); @@ -2204,6 +2204,12 @@ MarkGCThingChildren(JSContext *cx, void *thing, uint8 *flagp, goto start; #endif + case GCX_FUNCTION: + if (RECURSION_TOO_DEEP()) + goto add_to_unscanned_bag; + js_MarkFunction(cx, (JSFunction *)thing); + break; + #if JS_HAS_XML_SUPPORT case GCX_NAMESPACE: if (RECURSION_TOO_DEEP()) @@ -2435,6 +2441,7 @@ ScanDelayedChildren(JSContext *cx) */ switch (*flagp & GCF_TYPEMASK) { case GCX_OBJECT: + case GCX_FUNCTION: # if JS_HAS_XML_SUPPORT case GCX_NAMESPACE: case GCX_QNAME: @@ -3059,12 +3066,8 @@ restart: * so that any attempt to allocate a GC-thing from a finalizer will fail, * rather than nest badly and leave the unmarked newborn to be swept. * - * Here we need to ensure that JSObject instances are finalized before GC- - * allocated JSFunction instances so fun_finalize from jsfun.c can get the - * proper result from the call to js_IsAboutToBeFinalized. For that we - * simply finalize the list containing JSObject first since the static - * assert at the beginning of the file guarantees that JSFunction instances - * are allocated from a different list. + * Here we finalize the list containing JSObject first to ensure that + * JSObject finalizers can access JSString * and other GC things safely. */ for (i = 0; i < GC_NUM_FREELISTS; i++) { arenaList = &rt->gcArenaList[i == 0 @@ -3072,6 +3075,7 @@ restart: : i == GC_FREELIST_INDEX(sizeof(JSObject)) ? 0 : i]; + arenaList = &rt->gcArenaList[i]; nbytes = arenaList->thingSize; limit = arenaList->lastLimit; for (a = arenaList->last; a; a = a->prev) { diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 91e677698fb..2bcc8e7394a 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -55,7 +55,7 @@ JS_BEGIN_EXTERN_C #define GCX_DOUBLE 2 /* jsdouble */ #define GCX_MUTABLE_STRING 3 /* JSString that's mutable -- single-threaded only! */ -#define GCX_PRIVATE 4 /* private (unscanned) data */ +#define GCX_FUNCTION 4 /* JSFunction */ #define GCX_NAMESPACE 5 /* JSXMLNamespace */ #define GCX_QNAME 6 /* JSXMLQName */ #define GCX_XML 7 /* JSXML */ diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 22ac5fd56f8..be7621caa91 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -478,7 +478,7 @@ void XPCMarkNotification(void *thing, uint8 flags, void *closure) { uint8 ty = flags & GCF_TYPEMASK; if (ty != GCX_OBJECT && - ty != GCX_PRIVATE && + ty != GCX_FUNCTION && ty != GCX_XML) return;