From 9f9ab7cc1e7aeaf0b7d55a16883117187b9ce2b1 Mon Sep 17 00:00:00 2001 From: "igor.bukanov%gmail.com" Date: Wed, 21 Jun 2006 09:13:24 +0000 Subject: [PATCH] Bug 341877: Infrastructure to root properly native iterator states. r=brendan --- js/src/jscntxt.h | 11 +++++++++ js/src/jsgc.c | 1 + js/src/jsiter.c | 30 +----------------------- js/src/jsobj.c | 61 +++++++++++++++++++++++++++++++++++++----------- js/src/jsobj.h | 3 +++ js/src/jspubtd.h | 3 +-- js/src/jsxml.c | 6 ----- 7 files changed, 64 insertions(+), 51 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index cc95ad17fd19..34bb74b87768 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -108,6 +108,11 @@ typedef struct JSPropertyTreeEntry { JSScopeProperty *child; } JSPropertyTreeEntry; +/* + * Forward declaration for opaque JSRuntime.nativeIteratorStates. + */ +typedef struct JSNativeIteratorState JSNativeIteratorState; + struct JSRuntime { /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */ JSRuntimeState state; @@ -320,6 +325,12 @@ struct JSRuntime { JSObject *anynameObject; JSObject *functionNamespaceObject; + /* + * A helper list for the GC, so it can mark native iterator states. See + * js_MarkNativeIteratorStates for details. + */ + JSNativeIteratorState *nativeIteratorStates; + #ifdef DEBUG /* Function invocation metering. */ jsrefcount inlineCalls; diff --git a/js/src/jsgc.c b/js/src/jsgc.c index 81cff29bdcd7..1fe2dd295a93 100644 --- a/js/src/jsgc.c +++ b/js/src/jsgc.c @@ -2381,6 +2381,7 @@ restart: js_MarkAtomState(&rt->atomState, gcflags, gc_mark_atom_key_thing, cx); js_MarkWatchPoints(rt); js_MarkScriptFilenames(rt, gcflags); + js_MarkNativeIteratorStates(cx); iter = NULL; while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) { diff --git a/js/src/jsiter.c b/js/src/jsiter.c index eeb03f497d2d..30209793b418 100644 --- a/js/src/jsiter.c +++ b/js/src/jsiter.c @@ -76,33 +76,6 @@ extern const char js_throw_str[]; /* from jsscan.h */ #error JS_INITIAL_NSLOTS must be greater than JSSLOT_ITER_FLAGS. #endif -static uint32 -iterator_mark(JSContext *cx, JSObject *obj, void *arg) -{ - jsval state, parent; - JSObject *iterable; - - /* Avoid double work if js_CloseNativeIterator was called on obj. */ - state = obj->slots[JSSLOT_ITER_STATE]; - if (JSVAL_IS_VOID(state)) - return 0; - - parent = obj->slots[JSSLOT_PARENT]; - if (!JSVAL_IS_NULL(state) && !JSVAL_IS_PRIMITIVE(parent)) { - iterable = JSVAL_TO_OBJECT(parent); -#if JS_HAS_XML_SUPPORT - if ((JSVAL_TO_INT(obj->slots[JSSLOT_ITER_FLAGS]) & JSITER_FOREACH) && - OBJECT_IS_XML(cx, iterable)) { - ((JSXMLObjectOps *) iterable->map->ops)-> - enumerateValues(cx, iterable, JSENUMERATE_MARK, &state, - NULL, NULL); - } else -#endif - OBJ_ENUMERATE(cx, iterable, JSENUMERATE_MARK, &state, NULL); - } - return 0; -} - static void iterator_close(JSContext *cx, JSObject *obj) { @@ -137,8 +110,7 @@ JSExtendedClass js_IteratorClass = { JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, - NULL, NULL, NULL, NULL, - NULL, NULL, iterator_mark, NULL }, + JSCLASS_NO_OPTIONAL_MEMBERS }, NULL, NULL, NULL, iterator_close, JSCLASS_NO_RESERVED_MEMBERS }; diff --git a/js/src/jsobj.c b/js/src/jsobj.c index e968b3a3d964..a08cf2e4f4cf 100644 --- a/js/src/jsobj.c +++ b/js/src/jsobj.c @@ -3696,10 +3696,12 @@ js_SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length) } /* Private type used to iterate over all properties of a native JS object */ -typedef struct JSNativeIteratorState { - jsint next_index; /* index into jsid array */ - JSIdArray *ida; /* all property ids in enumeration */ -} JSNativeIteratorState; +struct JSNativeIteratorState { + jsint next_index; /* index into jsid array */ + JSIdArray *ida; /* all property ids in enumeration */ + JSNativeIteratorState *next; /* double-linked list support */ + JSNativeIteratorState **prevp; +}; /* * This function is used to enumerate the properties of native JSObjects @@ -3710,6 +3712,7 @@ JSBool js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp) { + JSRuntime *rt; JSObject *proto; JSClass *clasp; JSEnumerateOp enumerate; @@ -3719,6 +3722,7 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, JSIdArray *ida; JSNativeIteratorState *state; + rt = cx->runtime; clasp = OBJ_GET_CLASS(cx, obj); enumerate = clasp->enumerate; if (clasp->flags & JSCLASS_NEW_ENUMERATE) @@ -3795,6 +3799,15 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, } state->ida = ida; state->next_index = 0; + + JS_LOCK_RUNTIME(rt); + state->next = rt->nativeIteratorStates; + if (state->next) + state->next->prevp = &state->next; + state->prevp = &rt->nativeIteratorStates; + *state->prevp = state; + JS_UNLOCK_RUNTIME(rt); + *statep = PRIVATE_TO_JSVAL(state); if (idp) *idp = INT_TO_JSVAL(length); @@ -3812,28 +3825,48 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, case JSENUMERATE_DESTROY: state = (JSNativeIteratorState *) JSVAL_TO_PRIVATE(*statep); + + JS_LOCK_RUNTIME(rt); + JS_ASSERT(rt->nativeIteratorStates); + JS_ASSERT(*state->prevp == state); + if (state->next) { + JS_ASSERT(state->next->prevp == &state->next); + state->next->prevp = state->prevp; + } + *state->prevp = state->next; + JS_UNLOCK_RUNTIME(rt); + JS_DestroyIdArray(cx, state->ida); JS_free(cx, state); *statep = JSVAL_NULL; break; + } + return JS_TRUE; +} - case JSENUMERATE_MARK: - state = (JSNativeIteratorState *) JSVAL_TO_PRIVATE(*statep); - ida = state->ida; - length = ida->length; - for (i = 0; i < length; i++) { - jsid id; +void +js_MarkNativeIteratorStates(JSContext *cx) +{ + JSNativeIteratorState *state; + jsid *cursor, *end, id; - id = ida->vector[i]; + state = cx->runtime->nativeIteratorStates; + if (!state) + return; + + do { + JS_ASSERT(*state->prevp == state); + cursor = state->ida->vector; + end = cursor + state->ida->length; + for (; cursor != end; ++cursor) { + id = *cursor; if (JSID_IS_ATOM(id)) { GC_MARK_ATOM(cx, JSID_TO_ATOM(id)); } else if (JSID_IS_OBJECT(id)) { GC_MARK(cx, JSID_TO_OBJECT(id), "ida->vector[i]"); } } - break; - } - return JS_TRUE; + } while ((state = state->next) != NULL); } JSBool diff --git a/js/src/jsobj.h b/js/src/jsobj.h index e0226dc259c2..5615cd3a9e4b 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -498,6 +498,9 @@ extern JSBool js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp); +extern void +js_MarkNativeIteratorStates(JSContext *cx); + extern JSBool js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp, uintN *attrsp); diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 6fb0abd19647..e6e0871c2cd8 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -119,8 +119,7 @@ typedef enum JSAccessMode { typedef enum JSIterateOp { JSENUMERATE_INIT, /* Create new iterator state */ JSENUMERATE_NEXT, /* Iterate once */ - JSENUMERATE_DESTROY, /* Destroy iterator state */ - JSENUMERATE_MARK /* mark opaque iterator state */ + JSENUMERATE_DESTROY /* Destroy iterator state */ } JSIterateOp; /* Struct typedefs. */ diff --git a/js/src/jsxml.c b/js/src/jsxml.c index 868f8efa0a19..ff97665f4770 100644 --- a/js/src/jsxml.c +++ b/js/src/jsxml.c @@ -5151,9 +5151,6 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, } *statep = JSVAL_NULL; break; - - case JSENUMERATE_MARK: - break; } return JS_TRUE; } @@ -5313,9 +5310,6 @@ xml_enumerateValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, } *statep = JSVAL_NULL; break; - - case JSENUMERATE_MARK: - break; } return JS_TRUE; }