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_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:

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

@ -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;
}

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

@ -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;

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

@ -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<JSObject *>(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 */

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

@ -1765,8 +1765,9 @@ IsGCThresholdReached(JSRuntime *rt)
rt->gcBytes >= rt->gcTriggerBytes;
}
template <class T> static JS_INLINE T*
NewGCThing(JSContext *cx, uintN flags)
template <typename T, typename NewbornType>
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<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 *
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;

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

@ -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;

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

@ -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;

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

@ -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)

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

@ -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)

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

@ -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;