void ForInObjectEnumerator::Initialize(RecyclableObject* currentObject, ScriptContext * scriptContext) { Assert(propertyIds == nullptr); Assert(newPropertyStrings.Empty()); Assert(this->GetScriptContext() == scriptContext); this->currentIndex = nullptr; if (currentObject == nullptr) { currentEnumerator = scriptContext->GetLibrary()->GetNullEnumerator(); this->object = nullptr; this->baseObject = nullptr; this->baseObjectType = nullptr; this->firstPrototype = nullptr; return; } Assert(JavascriptOperators::GetTypeId(currentObject) != TypeIds_Null && JavascriptOperators::GetTypeId(currentObject) != TypeIds_Undefined); if (this->currentEnumerator != NULL && !VirtualTableInfo<Js::NullEnumerator>::HasVirtualTable(this->currentEnumerator) && this->object == currentObject && this->baseObjectType == currentObject->GetType()) { // We can re-use the enumerator, only if the 'object' and type from the previous enumeration // remains the same. If the previous enumeration involved prototype enumeration // 'object' and 'currentEnumerator' would represent the prototype. Hence, // we cannot re-use it. Null objects are always equal, therefore, the enumerator cannot // be re-used. currentEnumerator->Reset(); } else { this->baseObjectType = currentObject->GetType(); this->object = currentObject; GetCurrentEnumerator(); } this->baseObject = currentObject; firstPrototype = GetFirstPrototypeWithEnumerableProperties(object); if (firstPrototype != nullptr) { Recycler *recycler = scriptContext->GetRecycler(); propertyIds = RecyclerNew(recycler, BVSparse<Recycler>, recycler); } }
void ForInObjectEnumerator::Initialize(RecyclableObject* initObject, ScriptContext * requestContext, bool enumSymbols, ForInCache * forInCache) { this->enumeratingPrototype = false; if (initObject == nullptr) { enumerator.Clear(EnumeratorFlags::None, requestContext); this->shadowData = nullptr; this->canUseJitFastPath = false; return; } Assert(JavascriptOperators::GetTypeId(initObject) != TypeIds_Null && JavascriptOperators::GetTypeId(initObject) != TypeIds_Undefined); EnumeratorFlags flags; RecyclableObject * firstPrototype = nullptr; RecyclableObject * firstPrototypeWithEnumerableProperties = GetFirstPrototypeWithEnumerableProperties(initObject, &firstPrototype); if (firstPrototypeWithEnumerableProperties != nullptr) { Recycler *recycler = requestContext->GetRecycler(); this->shadowData = RecyclerNew(recycler, ShadowData, initObject, firstPrototype, recycler); flags = EnumeratorFlags::UseCache | EnumeratorFlags::SnapShotSemantics | EnumeratorFlags::EnumNonEnumerable | (enumSymbols ? EnumeratorFlags::EnumSymbols : EnumeratorFlags::None); } // no enumerable properties in the prototype chain, no need to search it else { this->shadowData = nullptr; flags = EnumeratorFlags::UseCache | EnumeratorFlags::SnapShotSemantics | (enumSymbols ? EnumeratorFlags::EnumSymbols : EnumeratorFlags::None); } if (InitializeCurrentEnumerator(initObject, flags, requestContext, forInCache)) { canUseJitFastPath = this->enumerator.CanUseJITFastPath(); } else { // Nothing to enumerate. // We keep the shadowData so that it may walk up the prototype chain (e.g. primitive type) enumerator.Clear(flags, requestContext); canUseJitFastPath = false; } }