static inline PropertyIteratorObject* VectorToKeyIterator(JSContext* cx, HandleObject obj, AutoIdVector& keys, uint32_t numGuards) { if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj)) return nullptr; MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED); Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx)); if (!iterobj) return nullptr; NativeIterator* ni = NativeIterator::allocateIterator(cx, numGuards, keys.length()); if (!ni) return nullptr; iterobj->setNativeIterator(ni); ni->init(obj, iterobj, numGuards, 0); if (!ni->initProperties(cx, iterobj, keys)) return nullptr; if (numGuards) { // Fill in the guard array from scratch. Also recompute the guard key // as we might have reshaped the object (see for instance the // setIteratedSingleton call above) or GC might have moved shapes and // groups in memory. JSObject* pobj = obj; size_t ind = 0; uint32_t key = 0; do { ReceiverGuard guard(pobj); ni->guard_array[ind++].init(guard); key = mozilla::AddToHash(key, guard.hash()); // The one caller of this method that passes |numGuards > 0|, does // so only if the entire chain consists of cacheable objects (that // necessarily have static prototypes). pobj = pobj->staticPrototype(); } while (pobj); ni->guard_key = key; MOZ_ASSERT(ind == numGuards); } RegisterEnumerator(cx, ni); return iterobj; }
// Mainly used for .. in over null/undefined JSObject* js::NewEmptyPropertyIterator(JSContext* cx) { Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx)); if (!iterobj) return nullptr; AutoIdVector keys(cx); // Empty NativeIterator* ni = NativeIterator::allocateIterator(cx, 0, keys.length()); if (!ni) return nullptr; iterobj->setNativeIterator(ni); ni->init(nullptr, iterobj, 0, 0); if (!ni->initProperties(cx, iterobj, keys)) return nullptr; RegisterEnumerator(cx, ni); return iterobj; }