static inline PropertyIteratorObject* NewPropertyIteratorObject(JSContext* cx) { RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PropertyIteratorObject::class_, TaggedProto(nullptr))); if (!group) return nullptr; const Class* clasp = &PropertyIteratorObject::class_; RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(nullptr), ITERATOR_FINALIZE_KIND)); if (!shape) return nullptr; JSObject* obj; JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, ITERATOR_FINALIZE_KIND, GetInitialHeap(GenericObject, clasp), shape, group)); PropertyIteratorObject* res = &obj->as<PropertyIteratorObject>(); // CodeGenerator::visitIteratorStartO assumes the iterator object is not // inside the nursery when deciding whether a barrier is necessary. MOZ_ASSERT(!js::gc::IsInsideNursery(res)); MOZ_ASSERT(res->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS); return res; }
static bool Reify(JSContext *cx, JSCompartment *origin, Value *vp) { PropertyIteratorObject *iterObj = &vp->toObject().asPropertyIterator(); NativeIterator *ni = iterObj->getNativeIterator(); AutoCloseIterator close(cx, iterObj); /* Wrap the iteratee. */ RootedObject obj(cx, ni->obj); if (!origin->wrap(cx, obj.address())) return false; /* * Wrap the elements in the iterator's snapshot. * N.B. the order of closing/creating iterators is important due to the * implicit cx->enumerators state. */ size_t length = ni->numKeys(); bool isKeyIter = ni->isKeyIter(); AutoIdVector keys(cx); if (length > 0) { if (!keys.reserve(length)) return false; for (size_t i = 0; i < length; ++i) { jsid id; if (!ValueToId(cx, StringValue(ni->begin()[i]), &id)) return false; keys.infallibleAppend(id); if (!origin->wrapId(cx, &keys[i])) return false; } } close.clear(); if (!CloseIterator(cx, iterObj)) return false; if (isKeyIter) return VectorToKeyIterator(cx, obj, ni->flags, keys, vp); return VectorToValueIterator(cx, obj, ni->flags, keys, vp); }
static MOZ_ALWAYS_INLINE PropertyIteratorObject* LookupInIteratorCache(JSContext* cx, JSObject* obj, uint32_t* numGuards) { MOZ_ASSERT(*numGuards == 0); ReceiverGuardVector guards(cx); uint32_t key = 0; JSObject* pobj = obj; do { if (!CanCompareIterableObjectToCache(pobj)) return nullptr; ReceiverGuard guard(pobj); key = mozilla::AddToHash(key, guard.hash()); if (MOZ_UNLIKELY(!guards.append(guard))) { cx->recoverFromOutOfMemory(); return nullptr; } pobj = pobj->staticPrototype(); } while (pobj); MOZ_ASSERT(!guards.empty()); *numGuards = guards.length(); IteratorHashPolicy::Lookup lookup(guards.begin(), guards.length(), key); auto p = cx->compartment()->iteratorCache.lookup(lookup); if (!p) return nullptr; PropertyIteratorObject* iterobj = *p; MOZ_ASSERT(iterobj->compartment() == cx->compartment()); NativeIterator* ni = iterobj->getNativeIterator(); if (ni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) return nullptr; return iterobj; }