JavascriptString * DynamicObjectPropertyEnumerator::MoveAndGetNextNoCache(PropertyId& propertyId, PropertyAttributes * attributes) { JavascriptString* propertyString = nullptr; BigPropertyIndex newIndex = this->objectIndex; PropertyValueInfo info; RecyclableObject * startingObject = this->object; do { newIndex++; PropertyValueInfo::ClearCacheInfo(&info); if (!this->object->FindNextProperty(newIndex, &propertyString, &propertyId, attributes, GetTypeToEnumerate(), flags, this->scriptContext, &info) || (GetSnapShotSemantics() && newIndex >= initialPropertyCount)) { // No more properties newIndex--; propertyString = nullptr; PropertyValueInfo::ClearCacheInfo(&info); break; } } while (Js::IsInternalPropertyId(propertyId)); if (info.GetPropertyRecordUsageCache() != nullptr && info.GetPropertyRecordUsageCache()->ShouldUseCache() && propertyString == info.GetProperty()) { CacheOperators::CachePropertyRead(startingObject, this->object, false, propertyId, false, &info, scriptContext); if ((!(this->flags & EnumeratorFlags::EphemeralReference)) && info.IsStoreFieldCacheEnabled() && info.IsWritable() && ((info.GetFlags() & (InlineCacheGetterFlag | InlineCacheSetterFlag)) == 0)) { PropertyValueInfo::SetCacheInfo(&info, info.GetPropertyRecordUsageCache()->GetStElemInlineCache(), info.AllowResizingPolymorphicInlineCache()); CacheOperators::CachePropertyWrite(this->object, false, this->object->GetType(), propertyId, &info, scriptContext); } } this->objectIndex = newIndex; return propertyString; }
DynamicType * DynamicObjectPropertyEnumerator::GetTypeToEnumerate() const { return GetSnapShotSemantics() && initialType->GetIsLocked() && CONFIG_FLAG(TypeSnapshotEnumeration) ? PointerValue(initialType) : object->GetDynamicType(); }
void DynamicObjectPropertyEnumerator::Reset() { if (this->object) { enumeratedCount = 0; initialType = object->GetDynamicType(); objectIndex = Constants::NoBigSlot; initialPropertyCount = GetSnapShotSemantics() ? this->object->GetPropertyCount() : Constants::NoBigSlot; // Create the appropriate enumerator object. if (GetSnapShotSemantics() && this->initialType->PrepareForTypeSnapshotEnumeration()) { ScriptContext* scriptContext = this->object->GetScriptContext(); ThreadContext * threadContext = scriptContext->GetThreadContext(); CachedData * data = (CachedData *)threadContext->GetDynamicObjectEnumeratorCache(this->initialType); if (data == nullptr || data->scriptContext != this->requestContext || data->enumNonEnumerable != GetEnumNonEnumerable() || data->enumSymbols != GetEnumSymbols()) { data = RecyclerNewStructPlus(scriptContext->GetRecycler(), this->initialPropertyCount * sizeof(PropertyString *) + this->initialPropertyCount * sizeof(BigPropertyIndex) + this->initialPropertyCount * sizeof(PropertyAttributes), CachedData); data->scriptContext = requestContext; data->cachedCount = 0; data->strings = (PropertyString **)(data + 1); data->indexes = (BigPropertyIndex *)(data->strings + this->initialPropertyCount); data->attributes = (PropertyAttributes*)(data->indexes + this->initialPropertyCount); data->completed = false; data->enumNonEnumerable = GetEnumNonEnumerable(); data->enumSymbols = GetEnumSymbols(); threadContext->AddDynamicObjectEnumeratorCache(this->initialType, data); } this->cachedData = data; this->cachedDataType = this->initialType; } else { this->cachedData = nullptr; this->cachedDataType = nullptr; } } }
JavascriptString * DynamicObjectPropertyEnumerator::MoveAndGetNextNoCache(PropertyId& propertyId, PropertyAttributes * attributes) { JavascriptString* propertyString = nullptr; BigPropertyIndex newIndex = this->objectIndex; do { newIndex++; if (!object->FindNextProperty(newIndex, &propertyString, &propertyId, attributes, GetTypeToEnumerate(), flags, this->scriptContext) || (GetSnapShotSemantics() && newIndex >= initialPropertyCount)) { // No more properties newIndex--; propertyString = nullptr; break; } } while (Js::IsInternalPropertyId(propertyId)); this->objectIndex = newIndex; return propertyString; }
bool DynamicObjectPropertyEnumerator::Initialize(DynamicObject * object, EnumeratorFlags flags, ScriptContext * requestContext, ForInCache * forInCache) { this->scriptContext = requestContext; this->object = object; this->flags = flags; if (!object) { this->cachedData = nullptr; return true; } this->objectIndex = Constants::NoBigSlot; this->enumeratedCount = 0; if (!GetUseCache()) { if (!object->GetDynamicType()->GetTypeHandler()->EnsureObjectReady(object)) { return false; } Initialize(object->GetDynamicType(), nullptr, GetSnapShotSemantics() ? this->object->GetPropertyCount() : Constants::NoBigSlot); return true; } DynamicType * type = object->GetDynamicType(); CachedData * data; if (forInCache && type == forInCache->type) { // We shouldn't have a for in cache when asking to enum symbols Assert(!GetEnumSymbols()); data = (CachedData *)forInCache->data; Assert(data != nullptr); Assert(data->scriptContext == this->scriptContext); // The cache data script context should be the same as request context Assert(!data->enumSymbols); if (data->enumNonEnumerable == GetEnumNonEnumerable()) { Initialize(type, data, data->propertyCount); return true; } } data = (CachedData *)requestContext->GetThreadContext()->GetDynamicObjectEnumeratorCache(type); if (data != nullptr && data->scriptContext == this->scriptContext && data->enumNonEnumerable == GetEnumNonEnumerable() && data->enumSymbols == GetEnumSymbols()) { Initialize(type, data, data->propertyCount); if (forInCache) { forInCache->type = type; forInCache->data = data; } return true; } if (!object->GetDynamicType()->GetTypeHandler()->EnsureObjectReady(object)) { return false; } // Reload the type after EnsureObjecteReady type = object->GetDynamicType(); if (!type->PrepareForTypeSnapshotEnumeration()) { Initialize(type, nullptr, object->GetPropertyCount()); return true; } uint propertyCount = this->object->GetPropertyCount(); data = RecyclerNewStructPlus(requestContext->GetRecycler(), propertyCount * sizeof(Field(PropertyString*)) + propertyCount * sizeof(BigPropertyIndex) + propertyCount * sizeof(PropertyAttributes), CachedData); data->scriptContext = requestContext; data->cachedCount = 0; data->propertyCount = propertyCount; data->strings = reinterpret_cast<Field(PropertyString*)*>(data + 1); data->indexes = (BigPropertyIndex *)(data->strings + propertyCount); data->attributes = (PropertyAttributes*)(data->indexes + propertyCount); data->completed = false; data->enumNonEnumerable = GetEnumNonEnumerable(); data->enumSymbols = GetEnumSymbols(); requestContext->GetThreadContext()->AddDynamicObjectEnumeratorCache(type, data); Initialize(type, data, propertyCount); if (forInCache) { forInCache->type = type; forInCache->data = data; } return true; }