diff --git a/js/src/jsgc.c b/js/src/jsgc.c index e4ef05643f2..a6c5ece2918 100644 --- a/js/src/jsgc.c +++ b/js/src/jsgc.c @@ -2289,6 +2289,9 @@ restart: } } + if (acx->sharpObjectMap.depth > 0) + js_GCMarkSharpMap(cx, &acx->sharpObjectMap); + acx->cachedIterObj = NULL; } diff --git a/js/src/jsobj.c b/js/src/jsobj.c index 69b161d100d..e658b5feaf0 100644 --- a/js/src/jsobj.c +++ b/js/src/jsobj.c @@ -648,6 +648,42 @@ js_LeaveSharpObject(JSContext *cx, JSIdArray **idap) } } +JS_STATIC_DLL_CALLBACK(intN) +gc_sharp_table_entry_marker(JSHashEntry *he, intN i, void *arg) +{ + GC_MARK((JSContext *)arg, (JSObject *)he->key, "sharp table entry"); + return JS_DHASH_NEXT; +} + +void +js_GCMarkSharpMap(JSContext *cx, JSSharpObjectMap *map) +{ + JS_ASSERT(map->depth > 0); + JS_ASSERT(map->table); + + /* + * During recursive calls to MarkSharpObjects a non-native object or + * object with a custom getProperty method can potentially return an + * unrooted value or even cut from the object graph an argument of one of + * MarkSharpObjects recursive invocations. So we must protect map->table + * entries against GC. + * + * We can not simply use JSTempValueRooter to mark the obj argument of + * MarkSharpObjects during recursion as we have to protect *all* entries + * in JSSharpObjectMap including those that contains otherwise unreachable + * objects just allocated through custom getProperty. Otherwise newer + * allocations can re-use the address of an object stored in the hashtable + * confusing js_EnterSharpObject. So to address the problem we simply + * mark all objects from map->table. + * + * An alternative "proper" solution is to use JSTempValueRooter in + * MarkSharpObjects with code to remove during finalization entries + * with otherwise unreachable objects. But this is way too complex + * to justify spending efforts. + */ + JS_HashTableEnumerateEntries(map->table, gc_sharp_table_entry_marker, cx); +} + #define OBJ_TOSTRING_EXTRA 4 /* for 4 local GC roots */ #if JS_HAS_TOSOURCE diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 5f76eac840d..e0226dc259c 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -304,6 +304,13 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, extern void js_LeaveSharpObject(JSContext *cx, JSIdArray **idap); +/* + * Mark objects stored in map if GC happens between js_EnterSharpObject + * and js_LeaveSharpObject. GC calls this when map->depth > 0. + */ +extern void +js_GCMarkSharpMap(JSContext *cx, JSSharpObjectMap *map); + extern JSBool js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);