bug 517199 - typed GC free lsists - newborn refactoring. r=brendan

This commit is contained in:
Igor Bukanov 2009-10-01 08:13:04 +04:00
Родитель f065057d5d
Коммит 2c25587f18
10 изменённых файлов: 86 добавлений и 78 удалений

Просмотреть файл

@ -2603,12 +2603,10 @@ JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
JS_PUBLIC_API(JSString *) JS_PUBLIC_API(JSString *)
JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type) JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
{ {
JSString *str;
CHECK_REQUEST(cx); 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) if (!str)
return NULL; return NULL;
str->initFlat(chars, length); str->initFlat(chars, length);
@ -4869,7 +4867,7 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
#endif #endif
out: out:
cx->weakRoots.newborn[JSTRACE_OBJECT] = FUN_OBJECT(fun); cx->weakRoots.newbornObject = FUN_OBJECT(fun);
JS_POP_TEMP_ROOT(cx, &tvr); JS_POP_TEMP_ROOT(cx, &tvr);
out2: out2:

Просмотреть файл

@ -3391,7 +3391,7 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto)
{ {
JS_ASSERT(OBJ_IS_ARRAY(cx, proto)); JS_ASSERT(OBJ_IS_ARRAY(cx, proto));
JSObject* obj = js_NewGCObject(cx, GCX_OBJECT); JSObject* obj = js_NewGCObject(cx);
if (!obj) if (!obj)
return NULL; return NULL;
@ -3463,7 +3463,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
JS_POP_TEMP_ROOT(cx, &tvr); JS_POP_TEMP_ROOT(cx, &tvr);
/* Set/clear newborn root, in case we lost it. */ /* Set/clear newborn root, in case we lost it. */
cx->weakRoots.newborn[GCX_OBJECT] = obj; cx->weakRoots.newbornObject = obj;
return obj; return obj;
} }

Просмотреть файл

@ -407,7 +407,7 @@ js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* pa
JSFunction *fun = (JSFunction*) funobj; JSFunction *fun = (JSFunction*) funobj;
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun); JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
JSObject* closure = js_NewGCObject(cx, GCX_OBJECT); JSObject* closure = js_NewGCObject(cx);
if (!closure) if (!closure)
return NULL; return NULL;

Просмотреть файл

@ -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 ***** * ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 * 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 #define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure
optimization level -- see above */ optimization level -- see above */
#define FUN_OBJECT(fun) (&(fun)->object) #define FUN_OBJECT(fun) (static_cast<JSObject *>(fun))
#define FUN_KIND(fun) ((fun)->flags & JSFUN_KINDMASK) #define FUN_KIND(fun) ((fun)->flags & JSFUN_KINDMASK)
#define FUN_SET_KIND(fun,k) ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k)) #define FUN_SET_KIND(fun,k) ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k))
#define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED) #define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED)
@ -128,8 +128,7 @@ typedef union JSLocalNames {
JS_ASSERT((fun)->flags & JSFUN_TRCINFO), \ JS_ASSERT((fun)->flags & JSFUN_TRCINFO), \
fun->u.n.trcinfo) fun->u.n.trcinfo)
struct JSFunction { struct JSFunction : public JSObject {
JSObject object; /* GC'ed object header */
uint16 nargs; /* maximum number of specified arguments, uint16 nargs; /* maximum number of specified arguments,
reflected as f.length/f.arity */ reflected as f.length/f.arity */
uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */ uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */

Просмотреть файл

@ -1765,8 +1765,9 @@ IsGCThresholdReached(JSRuntime *rt)
rt->gcBytes >= rt->gcTriggerBytes; rt->gcBytes >= rt->gcTriggerBytes;
} }
template <class T> static JS_INLINE T* template <typename T, typename NewbornType>
NewGCThing(JSContext *cx, uintN flags) static JS_INLINE T*
NewGCThing(JSContext *cx, uintN flags, NewbornType** newbornRoot)
{ {
JSRuntime *rt; JSRuntime *rt;
bool doGC; bool doGC;
@ -1995,7 +1996,7 @@ testReservedObjects:
* No local root scope, so we're stuck with the old, fragile model of * No local root scope, so we're stuck with the old, fragile model of
* depending on a pigeon-hole newborn per type per context. * 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. */ /* We can't fail now, so update flags. */
@ -2027,26 +2028,40 @@ fail:
return NULL; return NULL;
} }
extern JSObject* js_NewGCObject(JSContext *cx, uintN flags) JSObject *
js_NewGCObject(JSContext *cx)
{ {
return NewGCThing<JSObject>(cx, flags); return NewGCThing<JSObject>(cx, GCX_OBJECT, &cx->weakRoots.newbornObject);
} }
extern JSString* js_NewGCString(JSContext *cx, uintN flags) JSString *
js_NewGCString(JSContext *cx)
{ {
return NewGCThing<JSString>(cx, flags); return NewGCThing<JSString>(cx, GCX_STRING, &cx->weakRoots.newbornString);
} }
extern JSFunction* js_NewGCFunction(JSContext *cx, uintN flags) JSString *
js_NewGCExternalString(JSContext *cx, uintN type)
{ {
return NewGCThing<JSFunction>(cx, flags); JS_ASSERT(type < JS_EXTERNAL_STRING_LIMIT);
return NewGCThing<JSString>(cx, GCX_EXTERNAL_STRING + type,
&cx->weakRoots.newbornExternalString[type]);
} }
extern JSXML* js_NewGCXML(JSContext *cx, uintN flags) JSFunction *
js_NewGCFunction(JSContext *cx)
{ {
return NewGCThing<JSXML>(cx, flags); return NewGCThing<JSFunction>(cx, GCX_OBJECT, &cx->weakRoots.newbornObject);
} }
#if JS_HAS_XML_SUPPORT
JSXML *
js_NewGCXML(JSContext *cx)
{
return NewGCThing<JSXML>(cx, GCX_XML, &cx->weakRoots.newbornXML);
}
#endif
static JSGCDoubleCell * static JSGCDoubleCell *
RefillDoubleFreeList(JSContext *cx) RefillDoubleFreeList(JSContext *cx)
{ {
@ -2224,7 +2239,7 @@ js_NewWeaklyRootedDouble(JSContext *cx, jsdouble d)
if (js_PushLocalRoot(cx, cx->localRootStack, v) < 0) if (js_PushLocalRoot(cx, cx->localRootStack, v) < 0)
return NULL; return NULL;
} else { } else {
cx->weakRoots.newborn[GCX_DOUBLE] = dp; cx->weakRoots.newbornDouble = dp;
} }
return dp; return dp;
} }
@ -2240,7 +2255,7 @@ js_ReserveObjects(JSContext *cx, size_t nobjects)
JSObject *&head = JS_TRACE_MONITOR(cx).reservedObjects; JSObject *&head = JS_TRACE_MONITOR(cx).reservedObjects;
size_t i = head ? JSVAL_TO_INT(head->fslots[1]) : 0; size_t i = head ? JSVAL_TO_INT(head->fslots[1]) : 0;
while (i < nobjects) { while (i < nobjects) {
JSObject *obj = js_NewGCObject(cx, GCX_OBJECT); JSObject *obj = js_NewGCObject(cx);
if (!obj) if (!obj)
return JS_FALSE; return JS_FALSE;
memset(obj, 0, sizeof(JSObject)); memset(obj, 0, sizeof(JSObject));
@ -2889,33 +2904,21 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
static void static void
TraceWeakRoots(JSTracer *trc, JSWeakRoots *wr) TraceWeakRoots(JSTracer *trc, JSWeakRoots *wr)
{ {
uint32 i; if (wr->newbornObject)
void *thing; JS_CALL_OBJECT_TRACER(trc, wr->newbornObject, "newborn_object");
if (wr->newbornString)
#ifdef DEBUG JS_CALL_STRING_TRACER(trc, wr->newbornString, "newborn_string");
static const char *weakRootNames[JSTRACE_LIMIT] = { if (wr->newbornDouble)
"newborn object", JS_CALL_DOUBLE_TRACER(trc, wr->newbornDouble, "newborn_double");
"newborn double", #if JS_HAS_XML_SUPPORT
"newborn string", if (wr->newbornXML)
"newborn xml" JS_CALL_TRACER(trc, wr->newbornXML, JSTRACE_XML, "newborn_xml");
};
#endif #endif
for (uint32 i = 0; i != JS_EXTERNAL_STRING_LIMIT; i++) {
for (i = 0; i != JSTRACE_LIMIT; i++) { JSString *str = wr->newbornExternalString[i];
thing = wr->newborn[i]; if (str)
if (thing) JS_CALL_STRING_TRACER(trc, str, "newborn_external_string");
JS_CALL_TRACER(trc, thing, i, weakRootNames[i]);
} }
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_CALL_VALUE_TRACER(trc, wr->lastAtom, "lastAtom");
JS_SET_TRACING_NAME(trc, "lastInternalResult"); JS_SET_TRACING_NAME(trc, "lastInternalResult");
js_CallValueTracerIfGCThing(trc, wr->lastInternalResult); js_CallValueTracerIfGCThing(trc, wr->lastInternalResult);
@ -3213,7 +3216,8 @@ FinalizeObject(JSContext *cx, JSObject *obj)
js_FreeSlots(cx, 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 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
}; };
@ -3221,12 +3225,10 @@ intN
js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop, js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
JSStringFinalizeOp newop) JSStringFinalizeOp newop)
{ {
uintN i; for (uintN i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) {
for (i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) {
if (str_finalizers[i] == oldop) { if (str_finalizers[i] == oldop) {
str_finalizers[i] = newop; str_finalizers[i] = newop;
return (intN) i; return intN(i);
} }
} }
return -1; return -1;

Просмотреть файл

@ -68,11 +68,13 @@ JS_BEGIN_EXTERN_C
#define GCX_XML JSTRACE_XML /* JSXML */ #define GCX_XML JSTRACE_XML /* JSXML */
#define GCX_EXTERNAL_STRING JSTRACE_LIMIT /* JSString with external #define GCX_EXTERNAL_STRING JSTRACE_LIMIT /* JSString with external
chars */ chars */
const uintN JS_EXTERNAL_STRING_LIMIT = 8;
/* /*
* The number of defined GC types and the maximum limit for the number of * The number of defined GC types and the maximum limit for the number of
* possible GC types. * 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_LOG2 4 /* type index bits */
#define GCX_LIMIT JS_BIT(GCX_LIMIT_LOG2) #define GCX_LIMIT JS_BIT(GCX_LIMIT_LOG2)
@ -169,16 +171,19 @@ struct JSGCThing {
* values stored in the partially initialized thing. * values stored in the partially initialized thing.
*/ */
extern JSObject* extern JSObject*
js_NewGCObject(JSContext *cx, uintN flags); js_NewGCObject(JSContext *cx);
extern JSString* extern JSString*
js_NewGCString(JSContext *cx, uintN flags); js_NewGCString(JSContext *cx);
extern JSString*
js_NewGCExternalString(JSContext *cx, uintN type);
extern JSFunction* extern JSFunction*
js_NewGCFunction(JSContext *cx, uintN flags); js_NewGCFunction(JSContext *cx);
extern JSXML* 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. * 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 { struct JSWeakRoots {
/* Most recently created things by type, members of the GC's root set. */ /* 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. */ /* Atom root for the last-looked-up atom on this context. */
jsval lastAtom; jsval lastAtom;

Просмотреть файл

@ -2211,14 +2211,14 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
*/ */
JSObject* obj; JSObject* obj;
if (clasp == &js_FunctionClass && !objectSize) { if (clasp == &js_FunctionClass && !objectSize) {
obj = (JSObject*) js_NewGCFunction(cx, GCX_OBJECT); obj = (JSObject*) js_NewGCFunction(cx);
#ifdef DEBUG #ifdef DEBUG
memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN, memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
sizeof(JSFunction) - sizeof(JSObject)); sizeof(JSFunction) - sizeof(JSObject));
#endif #endif
} else { } else {
JS_ASSERT(!objectSize || objectSize == sizeof(JSObject)); JS_ASSERT(!objectSize || objectSize == sizeof(JSObject));
obj = js_NewGCObject(cx, GCX_OBJECT); obj = js_NewGCObject(cx);
} }
if (!obj) if (!obj)
goto out; goto out;
@ -2243,7 +2243,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
} }
/* Check that the newborn root still holds the object. */ /* 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 * 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->objectHook(cx, obj, JS_TRUE,
cx->debugHooks->objectHookData); cx->debugHooks->objectHookData);
JS_UNKEEP_ATOMS(cx->runtime); JS_UNKEEP_ATOMS(cx->runtime);
cx->weakRoots.newborn[GCX_OBJECT] = obj; cx->weakRoots.newbornObject = obj;
} }
out: out:
@ -2320,7 +2320,7 @@ NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto,
JSObject *parent, jsval privateSlotValue) JSObject *parent, jsval privateSlotValue)
{ {
JS_ASSERT(JS_ON_TRACE(cx)); JS_ASSERT(JS_ON_TRACE(cx));
JSObject* obj = js_NewGCObject(cx, GCX_OBJECT); JSObject* obj = js_NewGCObject(cx);
if (!obj) if (!obj)
return NULL; return NULL;
@ -2659,7 +2659,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
JS_ASSERT(!OBJ_IS_CLONED_BLOCK(proto)); JS_ASSERT(!OBJ_IS_CLONED_BLOCK(proto));
JS_ASSERT(STOBJ_GET_CLASS(proto) == &js_BlockClass); JS_ASSERT(STOBJ_GET_CLASS(proto) == &js_BlockClass);
JSObject *clone = js_NewGCObject(cx, GCX_OBJECT); JSObject *clone = js_NewGCObject(cx);
if (!clone) if (!clone)
return NULL; return NULL;
@ -3259,7 +3259,7 @@ js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto,
JS_ASSERT(proto->map->ops == &js_ObjectOps); JS_ASSERT(proto->map->ops == &js_ObjectOps);
JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp); JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp);
JSObject* obj = js_NewGCObject(cx, GCX_OBJECT); JSObject* obj = js_NewGCObject(cx);
if (!obj) if (!obj)
return NULL; return NULL;
@ -5508,7 +5508,7 @@ js_GetClassPrototype(JSContext *cx, JSObject *scope, jsid id,
* instance that delegates to this object, or just query the * instance that delegates to this object, or just query the
* prototype for its class. * 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; *protop = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL;

Просмотреть файл

@ -3483,7 +3483,7 @@
JS_ASSERT(regs.sp - StackBase(fp) >= 1); JS_ASSERT(regs.sp - StackBase(fp) >= 1);
lval = FETCH_OPND(-1); lval = FETCH_OPND(-1);
JS_ASSERT(JSVAL_IS_OBJECT(lval)); 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) END_CASE(JSOP_ENDINIT)
BEGIN_CASE(JSOP_INITPROP) BEGIN_CASE(JSOP_INITPROP)

Просмотреть файл

@ -3025,7 +3025,7 @@ js_NewString(JSContext *cx, jschar *chars, size_t length)
return NULL; return NULL;
} }
str = js_NewGCString(cx, GCX_STRING); str = js_NewGCString(cx);
if (!str) if (!str)
return NULL; return NULL;
str->initFlat(chars, length); 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); return js_NewStringCopyN(cx, base->chars() + start, length);
} }
ds = js_NewGCString(cx, GCX_STRING); ds = js_NewGCString(cx);
if (!ds) if (!ds)
return NULL; return NULL;
if (start == 0) if (start == 0)

Просмотреть файл

@ -3385,9 +3385,9 @@ Descendants(JSContext *cx, JSXML *xml, jsval id)
/* /*
* Protect nameqn's object and strings from GC by linking list to it * Protect nameqn's object and strings from GC by linking list to it
* temporarily. The cx->newborn[GCX_OBJECT] GC root protects listobj, * temporarily. The newborn GC root for the last allocated object
* which protects list. Any other object allocations occuring beneath * protects listobj, which protects list. Any other object allocations
* DescendantsHelper use local roots. * occurring beneath DescendantsHelper use local roots.
*/ */
list->name = nameqn; list->name = nameqn;
if (!js_EnterLocalRootScope(cx)) if (!js_EnterLocalRootScope(cx))
@ -7182,9 +7182,7 @@ uint32 xml_serial;
JSXML * JSXML *
js_NewXML(JSContext *cx, JSXMLClass xml_class) js_NewXML(JSContext *cx, JSXMLClass xml_class)
{ {
JSXML *xml; JSXML *xml = js_NewGCXML(cx);
xml = (JSXML *) js_NewGCXML(cx, GCX_XML);
if (!xml) if (!xml)
return NULL; return NULL;