From 2c25587f18a04ce6e10ddaf92d66abdbc14b1d57 Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Thu, 1 Oct 2009 08:13:04 +0400 Subject: [PATCH] bug 517199 - typed GC free lsists - newborn refactoring. r=brendan --- js/src/jsapi.cpp | 8 ++-- js/src/jsarray.cpp | 4 +- js/src/jsbuiltins.cpp | 2 +- js/src/jsfun.h | 7 ++-- js/src/jsgc.cpp | 88 ++++++++++++++++++++++--------------------- js/src/jsgc.h | 23 ++++++++--- js/src/jsobj.cpp | 16 ++++---- js/src/jsops.cpp | 2 +- js/src/jsstr.cpp | 4 +- js/src/jsxml.cpp | 10 ++--- 10 files changed, 86 insertions(+), 78 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f4eb380ff764..8d5ec426b384 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2603,12 +2603,10 @@ JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer) JS_PUBLIC_API(JSString *) JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type) { - JSString *str; - CHECK_REQUEST(cx); - JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING)); + JS_ASSERT(uintN(type) < JS_EXTERNAL_STRING_LIMIT); - str = js_NewGCString(cx, (uintN) type + GCX_EXTERNAL_STRING); + JSString *str = js_NewGCExternalString(cx, uintN(type)); if (!str) return NULL; str->initFlat(chars, length); @@ -4869,7 +4867,7 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, #endif out: - cx->weakRoots.newborn[JSTRACE_OBJECT] = FUN_OBJECT(fun); + cx->weakRoots.newbornObject = FUN_OBJECT(fun); JS_POP_TEMP_ROOT(cx, &tvr); out2: diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 9a9984e70e06..e1e0e3b26115 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3391,7 +3391,7 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto) { JS_ASSERT(OBJ_IS_ARRAY(cx, proto)); - JSObject* obj = js_NewGCObject(cx, GCX_OBJECT); + JSObject* obj = js_NewGCObject(cx); if (!obj) return NULL; @@ -3463,7 +3463,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey) JS_POP_TEMP_ROOT(cx, &tvr); /* Set/clear newborn root, in case we lost it. */ - cx->weakRoots.newborn[GCX_OBJECT] = obj; + cx->weakRoots.newbornObject = obj; return obj; } diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp index 6e9a98813927..a0b4de0d0578 100644 --- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -407,7 +407,7 @@ js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* pa JSFunction *fun = (JSFunction*) funobj; JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun); - JSObject* closure = js_NewGCObject(cx, GCX_OBJECT); + JSObject* closure = js_NewGCObject(cx); if (!closure) return NULL; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 069b7f4c2b05..158b19b38cc7 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -1,4 +1,4 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -107,7 +107,7 @@ typedef union JSLocalNames { #define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure optimization level -- see above */ -#define FUN_OBJECT(fun) (&(fun)->object) +#define FUN_OBJECT(fun) (static_cast(fun)) #define FUN_KIND(fun) ((fun)->flags & JSFUN_KINDMASK) #define FUN_SET_KIND(fun,k) ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k)) #define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED) @@ -128,8 +128,7 @@ typedef union JSLocalNames { JS_ASSERT((fun)->flags & JSFUN_TRCINFO), \ fun->u.n.trcinfo) -struct JSFunction { - JSObject object; /* GC'ed object header */ +struct JSFunction : public JSObject { uint16 nargs; /* maximum number of specified arguments, reflected as f.length/f.arity */ uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index e4bd3383176d..34701c4bfa98 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1765,8 +1765,9 @@ IsGCThresholdReached(JSRuntime *rt) rt->gcBytes >= rt->gcTriggerBytes; } -template static JS_INLINE T* -NewGCThing(JSContext *cx, uintN flags) +template +static JS_INLINE T* +NewGCThing(JSContext *cx, uintN flags, NewbornType** newbornRoot) { JSRuntime *rt; bool doGC; @@ -1995,7 +1996,7 @@ testReservedObjects: * No local root scope, so we're stuck with the old, fragile model of * depending on a pigeon-hole newborn per type per context. */ - cx->weakRoots.newborn[flags & GCF_TYPEMASK] = thing; + *newbornRoot = (T *) thing; } /* We can't fail now, so update flags. */ @@ -2027,26 +2028,40 @@ fail: return NULL; } -extern JSObject* js_NewGCObject(JSContext *cx, uintN flags) +JSObject * +js_NewGCObject(JSContext *cx) { - return NewGCThing(cx, flags); + return NewGCThing(cx, GCX_OBJECT, &cx->weakRoots.newbornObject); } -extern JSString* js_NewGCString(JSContext *cx, uintN flags) +JSString * +js_NewGCString(JSContext *cx) { - return NewGCThing(cx, flags); + return NewGCThing(cx, GCX_STRING, &cx->weakRoots.newbornString); } -extern JSFunction* js_NewGCFunction(JSContext *cx, uintN flags) +JSString * +js_NewGCExternalString(JSContext *cx, uintN type) { - return NewGCThing(cx, flags); + JS_ASSERT(type < JS_EXTERNAL_STRING_LIMIT); + return NewGCThing(cx, GCX_EXTERNAL_STRING + type, + &cx->weakRoots.newbornExternalString[type]); } -extern JSXML* js_NewGCXML(JSContext *cx, uintN flags) +JSFunction * +js_NewGCFunction(JSContext *cx) { - return NewGCThing(cx, flags); + return NewGCThing(cx, GCX_OBJECT, &cx->weakRoots.newbornObject); } +#if JS_HAS_XML_SUPPORT +JSXML * +js_NewGCXML(JSContext *cx) +{ + return NewGCThing(cx, GCX_XML, &cx->weakRoots.newbornXML); +} +#endif + static JSGCDoubleCell * RefillDoubleFreeList(JSContext *cx) { @@ -2224,7 +2239,7 @@ js_NewWeaklyRootedDouble(JSContext *cx, jsdouble d) if (js_PushLocalRoot(cx, cx->localRootStack, v) < 0) return NULL; } else { - cx->weakRoots.newborn[GCX_DOUBLE] = dp; + cx->weakRoots.newbornDouble = dp; } return dp; } @@ -2240,7 +2255,7 @@ js_ReserveObjects(JSContext *cx, size_t nobjects) JSObject *&head = JS_TRACE_MONITOR(cx).reservedObjects; size_t i = head ? JSVAL_TO_INT(head->fslots[1]) : 0; while (i < nobjects) { - JSObject *obj = js_NewGCObject(cx, GCX_OBJECT); + JSObject *obj = js_NewGCObject(cx); if (!obj) return JS_FALSE; memset(obj, 0, sizeof(JSObject)); @@ -2889,33 +2904,21 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) static void TraceWeakRoots(JSTracer *trc, JSWeakRoots *wr) { - uint32 i; - void *thing; - -#ifdef DEBUG - static const char *weakRootNames[JSTRACE_LIMIT] = { - "newborn object", - "newborn double", - "newborn string", - "newborn xml" - }; + if (wr->newbornObject) + JS_CALL_OBJECT_TRACER(trc, wr->newbornObject, "newborn_object"); + if (wr->newbornString) + JS_CALL_STRING_TRACER(trc, wr->newbornString, "newborn_string"); + if (wr->newbornDouble) + JS_CALL_DOUBLE_TRACER(trc, wr->newbornDouble, "newborn_double"); +#if JS_HAS_XML_SUPPORT + if (wr->newbornXML) + JS_CALL_TRACER(trc, wr->newbornXML, JSTRACE_XML, "newborn_xml"); #endif - - for (i = 0; i != JSTRACE_LIMIT; i++) { - thing = wr->newborn[i]; - if (thing) - JS_CALL_TRACER(trc, thing, i, weakRootNames[i]); + for (uint32 i = 0; i != JS_EXTERNAL_STRING_LIMIT; i++) { + JSString *str = wr->newbornExternalString[i]; + if (str) + JS_CALL_STRING_TRACER(trc, str, "newborn_external_string"); } - JS_ASSERT(i == GCX_EXTERNAL_STRING); - for (; i != GCX_NTYPES; ++i) { - thing = wr->newborn[i]; - if (thing) { - JS_SET_TRACING_INDEX(trc, "newborn external string", - i - GCX_EXTERNAL_STRING); - JS_CallTracer(trc, thing, JSTRACE_STRING); - } - } - JS_CALL_VALUE_TRACER(trc, wr->lastAtom, "lastAtom"); JS_SET_TRACING_NAME(trc, "lastInternalResult"); js_CallValueTracerIfGCThing(trc, wr->lastInternalResult); @@ -3213,7 +3216,8 @@ FinalizeObject(JSContext *cx, JSObject *obj) js_FreeSlots(cx, obj); } -static JSStringFinalizeOp str_finalizers[GCX_NTYPES - GCX_EXTERNAL_STRING] = { +JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8); +static JSStringFinalizeOp str_finalizers[JS_EXTERNAL_STRING_LIMIT] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; @@ -3221,12 +3225,10 @@ intN js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop, JSStringFinalizeOp newop) { - uintN i; - - for (i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) { + for (uintN i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) { if (str_finalizers[i] == oldop) { str_finalizers[i] = newop; - return (intN) i; + return intN(i); } } return -1; diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 4710dd0df59d..2cbc8d4b4a56 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -68,11 +68,13 @@ JS_BEGIN_EXTERN_C #define GCX_XML JSTRACE_XML /* JSXML */ #define GCX_EXTERNAL_STRING JSTRACE_LIMIT /* JSString with external chars */ +const uintN JS_EXTERNAL_STRING_LIMIT = 8; + /* * The number of defined GC types and the maximum limit for the number of * possible GC types. */ -#define GCX_NTYPES (GCX_EXTERNAL_STRING + 8) +#define GCX_NTYPES (GCX_EXTERNAL_STRING + JS_EXTERNAL_STRING_LIMIT) #define GCX_LIMIT_LOG2 4 /* type index bits */ #define GCX_LIMIT JS_BIT(GCX_LIMIT_LOG2) @@ -169,16 +171,19 @@ struct JSGCThing { * values stored in the partially initialized thing. */ extern JSObject* -js_NewGCObject(JSContext *cx, uintN flags); +js_NewGCObject(JSContext *cx); extern JSString* -js_NewGCString(JSContext *cx, uintN flags); +js_NewGCString(JSContext *cx); + +extern JSString* +js_NewGCExternalString(JSContext *cx, uintN type); extern JSFunction* -js_NewGCFunction(JSContext *cx, uintN flags); +js_NewGCFunction(JSContext *cx); extern JSXML* -js_NewGCXML(JSContext *cx, uintN flags); +js_NewGCXML(JSContext *cx); /* * Allocate a new double jsval and store the result in *vp. vp must be a root. @@ -315,7 +320,13 @@ js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data); struct JSWeakRoots { /* Most recently created things by type, members of the GC's root set. */ - void *newborn[GCX_NTYPES]; + JSObject *newbornObject; + jsdouble *newbornDouble; + JSString *newbornString; +#if JS_HAS_XML_SUPPORT + JSXML *newbornXML; +#endif + JSString *newbornExternalString[JS_EXTERNAL_STRING_LIMIT]; /* Atom root for the last-looked-up atom on this context. */ jsval lastAtom; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index f89299c3fca6..6d6f7723b9a8 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2211,14 +2211,14 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, */ JSObject* obj; if (clasp == &js_FunctionClass && !objectSize) { - obj = (JSObject*) js_NewGCFunction(cx, GCX_OBJECT); + obj = (JSObject*) js_NewGCFunction(cx); #ifdef DEBUG memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN, sizeof(JSFunction) - sizeof(JSObject)); #endif } else { JS_ASSERT(!objectSize || objectSize == sizeof(JSObject)); - obj = js_NewGCObject(cx, GCX_OBJECT); + obj = js_NewGCObject(cx); } if (!obj) goto out; @@ -2243,7 +2243,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, } /* Check that the newborn root still holds the object. */ - JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newborn[GCX_OBJECT] == obj); + JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newbornObject == obj); /* * Do not call debug hooks on trace, because we might be in a non-_FAIL @@ -2255,7 +2255,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, cx->debugHooks->objectHook(cx, obj, JS_TRUE, cx->debugHooks->objectHookData); JS_UNKEEP_ATOMS(cx->runtime); - cx->weakRoots.newborn[GCX_OBJECT] = obj; + cx->weakRoots.newbornObject = obj; } out: @@ -2320,7 +2320,7 @@ NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto, JSObject *parent, jsval privateSlotValue) { JS_ASSERT(JS_ON_TRACE(cx)); - JSObject* obj = js_NewGCObject(cx, GCX_OBJECT); + JSObject* obj = js_NewGCObject(cx); if (!obj) return NULL; @@ -2659,7 +2659,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp) JS_ASSERT(!OBJ_IS_CLONED_BLOCK(proto)); JS_ASSERT(STOBJ_GET_CLASS(proto) == &js_BlockClass); - JSObject *clone = js_NewGCObject(cx, GCX_OBJECT); + JSObject *clone = js_NewGCObject(cx); if (!clone) return NULL; @@ -3259,7 +3259,7 @@ js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, JS_ASSERT(proto->map->ops == &js_ObjectOps); JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp); - JSObject* obj = js_NewGCObject(cx, GCX_OBJECT); + JSObject* obj = js_NewGCObject(cx); if (!obj) return NULL; @@ -5508,7 +5508,7 @@ js_GetClassPrototype(JSContext *cx, JSObject *scope, jsid id, * instance that delegates to this object, or just query the * prototype for its class. */ - cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(v); + cx->weakRoots.newbornObject = JSVAL_TO_OBJECT(v); } } *protop = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL; diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index b28045f22673..79c49bd3601e 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -3483,7 +3483,7 @@ JS_ASSERT(regs.sp - StackBase(fp) >= 1); lval = FETCH_OPND(-1); JS_ASSERT(JSVAL_IS_OBJECT(lval)); - cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(lval); + cx->weakRoots.newbornObject = JSVAL_TO_OBJECT(lval); END_CASE(JSOP_ENDINIT) BEGIN_CASE(JSOP_INITPROP) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 2159a64f80dd..c6ea23dae59d 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3025,7 +3025,7 @@ js_NewString(JSContext *cx, jschar *chars, size_t length) return NULL; } - str = js_NewGCString(cx, GCX_STRING); + str = js_NewGCString(cx); if (!str) return NULL; str->initFlat(chars, length); @@ -3095,7 +3095,7 @@ js_NewDependentString(JSContext *cx, JSString *base, size_t start, return js_NewStringCopyN(cx, base->chars() + start, length); } - ds = js_NewGCString(cx, GCX_STRING); + ds = js_NewGCString(cx); if (!ds) return NULL; if (start == 0) diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 5621edee82e3..53df64fa4186 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -3385,9 +3385,9 @@ Descendants(JSContext *cx, JSXML *xml, jsval id) /* * Protect nameqn's object and strings from GC by linking list to it - * temporarily. The cx->newborn[GCX_OBJECT] GC root protects listobj, - * which protects list. Any other object allocations occuring beneath - * DescendantsHelper use local roots. + * temporarily. The newborn GC root for the last allocated object + * protects listobj, which protects list. Any other object allocations + * occurring beneath DescendantsHelper use local roots. */ list->name = nameqn; if (!js_EnterLocalRootScope(cx)) @@ -7182,9 +7182,7 @@ uint32 xml_serial; JSXML * js_NewXML(JSContext *cx, JSXMLClass xml_class) { - JSXML *xml; - - xml = (JSXML *) js_NewGCXML(cx, GCX_XML); + JSXML *xml = js_NewGCXML(cx); if (!xml) return NULL;