/* * Shared code to close iterator's state either through an explicit call or * when GC detects that the iterator is no longer reachable. */ void js_CloseNativeIterator(JSContext *cx, JSObject *iterobj) { jsval state; JSObject *iterable; JS_ASSERT(iterobj->getClass() == &js_IteratorClass); /* Avoid double work if js_CloseNativeIterator was called on obj. */ state = iterobj->getSlot(JSSLOT_ITER_STATE); if (JSVAL_IS_NULL(state)) return; /* Protect against failure to fully initialize obj. */ iterable = iterobj->getParent(); if (iterable) { #if JS_HAS_XML_SUPPORT uintN flags = JSVAL_TO_INT(iterobj->getSlot(JSSLOT_ITER_FLAGS)); if ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, iterable)) { js_EnumerateXMLValues(cx, iterable, JSENUMERATE_DESTROY, &state, NULL, NULL); } else #endif iterable->enumerate(cx, JSENUMERATE_DESTROY, &state, NULL); } iterobj->setSlot(JSSLOT_ITER_STATE, JSVAL_NULL); }
static JSBool IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval) { JSObject *iterable; jsval state; uintN flags; JSBool foreach, ok; jsid id; JS_ASSERT(obj->getClass() == &js_IteratorClass); iterable = obj->getParent(); JS_ASSERT(iterable); state = obj->getSlot(JSSLOT_ITER_STATE); if (JSVAL_IS_NULL(state)) goto stop; flags = JSVAL_TO_INT(obj->getSlot(JSSLOT_ITER_FLAGS)); JS_ASSERT(!(flags & JSITER_ENUMERATE)); foreach = (flags & JSITER_FOREACH) != 0; ok = #if JS_HAS_XML_SUPPORT (foreach && OBJECT_IS_XML(cx, iterable)) ? js_EnumerateXMLValues(cx, iterable, JSENUMERATE_NEXT, &state, &id, rval) : #endif iterable->enumerate(cx, JSENUMERATE_NEXT, &state, &id); if (!ok) return JS_FALSE; obj->setSlot(JSSLOT_ITER_STATE, state); if (JSVAL_IS_NULL(state)) goto stop; if (foreach) { #if JS_HAS_XML_SUPPORT if (!OBJECT_IS_XML(cx, iterable) && !iterable->getProperty(cx, id, rval)) { return JS_FALSE; } #endif if (!NewKeyValuePair(cx, id, *rval, rval)) return JS_FALSE; } else { *rval = ID_TO_VALUE(id); } return JS_TRUE; stop: JS_ASSERT(obj->getSlot(JSSLOT_ITER_STATE) == JSVAL_NULL); *rval = JSVAL_HOLE; return JS_TRUE; }
static bool Snapshot(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector *props) { IdSet ht(cx); if (!ht.init(32)) return NULL; JSObject *pobj = obj; do { Class *clasp = pobj->getClass(); if (pobj->isNative() && !pobj->getOps()->enumerate && !(clasp->flags & JSCLASS_NEW_ENUMERATE)) { if (!clasp->enumerate(cx, pobj)) return false; if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) return false; } else if (pobj->isDenseArray()) { if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props)) return false; } else { if (pobj->isProxy()) { AutoIdVector proxyProps(cx); if (flags & JSITER_OWNONLY) { if (flags & JSITER_HIDDEN) { if (!JSProxy::getOwnPropertyNames(cx, pobj, proxyProps)) return false; } else { if (!JSProxy::keys(cx, pobj, proxyProps)) return false; } } else { if (!JSProxy::enumerate(cx, pobj, proxyProps)) return false; } for (size_t n = 0, len = proxyProps.length(); n < len; n++) { if (!Enumerate(cx, obj, pobj, proxyProps[n], true, flags, ht, props)) return false; } /* Proxy objects enumerate the prototype on their own, so we are done here. */ break; } Value state; JSIterateOp op = (flags & JSITER_HIDDEN) ? JSENUMERATE_INIT_ALL : JSENUMERATE_INIT; if (!pobj->enumerate(cx, op, &state, NULL)) return false; if (state.isMagic(JS_NATIVE_ENUMERATE)) { if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) return false; } else { while (true) { jsid id; if (!pobj->enumerate(cx, JSENUMERATE_NEXT, &state, &id)) return false; if (state.isNull()) break; if (!Enumerate(cx, obj, pobj, id, true, flags, ht, props)) return false; } } } if ((flags & JSITER_OWNONLY) || pobj->isXML()) break; } while ((pobj = pobj->getProto()) != NULL); return true; }