diff --git a/lib/Runtime/Library/JSONStringifier.cpp b/lib/Runtime/Library/JSONStringifier.cpp index 6c3e20eab22..b66480985e3 100644 --- a/lib/Runtime/Library/JSONStringifier.cpp +++ b/lib/Runtime/Library/JSONStringifier.cpp @@ -198,7 +198,6 @@ JSONStringifier::Stringify(_In_ ScriptContext* scriptContext, _In_ Var value, _I wrapper, prop, value, - scriptContext->GetThreadContext()->GetEmptyStringPropertyRecord(), &objStack); if (prop->type == JSONContentType::Undefined) @@ -340,7 +339,7 @@ JSONStringifier::ReadArrayElement(uint32 index, _In_ RecyclableObject* arr, _Out JavascriptOperators::GetItem(arr, index, &value, this->scriptContext); } JavascriptString* indexString = this->scriptContext->GetIntegerString(index); - this->ReadProperty(indexString, arr, prop, value, nullptr, objectStack); + this->ReadProperty(indexString, arr, prop, value, objectStack); } JSONArray* @@ -386,19 +385,13 @@ JSONStringifier::ReadArray(_In_ RecyclableObject* arr, _In_ JSONObjectStack* obj } void -JSONStringifier::ReadObjectElement( +JSONStringifier::AppendObjectElement( _In_ JavascriptString* propertyName, - _In_opt_ PropertyRecord const* propertyRecord, - _In_ RecyclableObject* obj, _In_ JSONObject* jsonObject, - _In_ JSONObjectStack* objectStack) + _In_ JSONObjectProperty* prop) { - JSONObjectProperty prop; - prop.propertyName = propertyName; - this->ReadProperty(propertyName, obj, &prop.propertyValue, nullptr, propertyRecord, objectStack); - // Undefined result is not concatenated - if (prop.propertyValue.type != JSONContentType::Undefined) + if (prop->propertyValue.type != JSONContentType::Undefined) { // Increase length for the name of the property this->totalStringLength = UInt32Math::Add(this->totalStringLength, CalculateStringElementLength(propertyName)); @@ -409,10 +402,47 @@ JSONStringifier::ReadObjectElement( // If gap is specified, a space is appended UInt32Math::Inc(this->totalStringLength); } - jsonObject->Push(prop); + + jsonObject->Push(*prop); } } +void +JSONStringifier::ReadObjectElement( + _In_ JavascriptString* propertyName, + _In_ uint32 numericIndex, + _In_ RecyclableObject* obj, + _In_ JSONObject* jsonObject, + _In_ JSONObjectStack* objectStack) +{ + JSONObjectProperty prop; + prop.propertyName = propertyName; + + Var value = JavascriptOperators::GetItem(obj, numericIndex, this->scriptContext); + + this->ReadProperty(propertyName, obj, &prop.propertyValue, value, objectStack); + + this->AppendObjectElement(propertyName, jsonObject, &prop); +} + +void +JSONStringifier::ReadObjectElement( + _In_ JavascriptString* propertyName, + _In_opt_ PropertyRecord const* propertyRecord, + _In_ RecyclableObject* obj, + _In_ JSONObject* jsonObject, + _In_ JSONObjectStack* objectStack) +{ + JSONObjectProperty prop; + prop.propertyName = propertyName; + + Var value = this->ReadValue(propertyName, propertyRecord, obj); + + this->ReadProperty(propertyName, obj, &prop.propertyValue, value, objectStack); + + this->AppendObjectElement(propertyName, jsonObject, &prop); +} + // Calculates how many additional characters are needed for printing the Object/Array structure // This includes commas, brackets, and gap (if any) void @@ -520,18 +550,25 @@ JSONStringifier::ReadObject(_In_ RecyclableObject* obj, _In_ JSONObjectStack* ob JavascriptStaticEnumerator enumerator; if (obj->GetEnumerator(&enumerator, EnumeratorFlags::SnapShotSemantics | EnumeratorFlags::EphemeralReference, this->scriptContext)) { - enumerator.GetInitialPropertyCount(); JavascriptString* propertyName = nullptr; PropertyId nextKey = Constants::NoProperty; while ((propertyName = enumerator.MoveAndGetNext(nextKey)) != nullptr) { - PropertyRecord const * propertyRecord = nullptr; - if (nextKey == Constants::NoProperty) + const uint32 numericIndex = enumerator.GetCurrentItemIndex(); + if (numericIndex != Constants::InvalidSourceIndex) + { + this->ReadObjectElement(propertyName, numericIndex, obj, jsonObject, &stack); + } + else { - this->scriptContext->GetOrAddPropertyRecord(propertyName, &propertyRecord); - nextKey = propertyRecord->GetPropertyId(); + PropertyRecord const * propertyRecord = nullptr; + if (nextKey == Constants::NoProperty) + { + this->scriptContext->GetOrAddPropertyRecord(propertyName, &propertyRecord); + nextKey = propertyRecord->GetPropertyId(); + } + this->ReadObjectElement(propertyName, propertyRecord, obj, jsonObject, &stack); } - this->ReadObjectElement(propertyName, propertyRecord, obj, jsonObject, &stack); } } } @@ -728,17 +765,10 @@ JSONStringifier::ReadProperty( _In_ JavascriptString* key, _In_opt_ RecyclableObject* holder, _Out_ JSONProperty* prop, - _In_opt_ Var value, - _In_opt_ const PropertyRecord* propertyRecord, + _In_ Var value, _In_ JSONObjectStack* objectStack) { PROBE_STACK(this->scriptContext, Constants::MinStackDefault); - if (value == nullptr) - { - // If we don't have a value, we must have an object from which we can read it - AnalysisAssert(holder != nullptr); - value = this->ReadValue(key, propertyRecord, holder); - } // Save these to avoid having to recheck conditions unless value is modified by ToJSON or a replacer function RecyclableObject* valueObj = JavascriptOperators::TryFromVar(value); diff --git a/lib/Runtime/Library/JSONStringifier.h b/lib/Runtime/Library/JSONStringifier.h index 31c0098ef47..0db957bfa59 100644 --- a/lib/Runtime/Library/JSONStringifier.h +++ b/lib/Runtime/Library/JSONStringifier.h @@ -63,6 +63,18 @@ class JSONStringifier uint32 ReadArrayLength(_In_ RecyclableObject* value); JSONArray* ReadArray(_In_ RecyclableObject* arr, _In_ JSONObjectStack* objectStack); + void AppendObjectElement( + _In_ JavascriptString* propertyName, + _In_ JSONObject* jsonObject, + _In_ JSONObjectProperty* prop); + + void ReadObjectElement( + _In_ JavascriptString* propertyName, + _In_ uint32 numericIndex, + _In_ RecyclableObject* obj, + _In_ JSONObject* jsonObject, + _In_ JSONObjectStack* objectStack); + void ReadObjectElement( _In_ JavascriptString* propertyName, _In_opt_ PropertyRecord const* propertyRecord, @@ -95,8 +107,7 @@ class JSONStringifier _In_ JavascriptString* key, _In_opt_ RecyclableObject* holder, _Out_ JSONProperty* prop, - _In_opt_ Var value, - _In_opt_ const PropertyRecord* propertyRecord, + _In_ Var value, _In_ JSONObjectStack* objectStack); const char16* GetGap() const { return this->gap; }; diff --git a/lib/Runtime/Library/JavascriptStringEnumerator.h b/lib/Runtime/Library/JavascriptStringEnumerator.h index 27772ef3934..003648c2127 100644 --- a/lib/Runtime/Library/JavascriptStringEnumerator.h +++ b/lib/Runtime/Library/JavascriptStringEnumerator.h @@ -18,5 +18,6 @@ namespace Js JavascriptStringEnumerator(JavascriptString* stringObject, ScriptContext * requestContext); virtual void Reset() override; virtual JavascriptString * MoveAndGetNext(PropertyId& propertyId, PropertyAttributes* attributes = nullptr) override; + virtual uint32 GetCurrentItemIndex() override { return index; } }; } diff --git a/lib/Runtime/Library/TypedArrayIndexEnumerator.h b/lib/Runtime/Library/TypedArrayIndexEnumerator.h index 9872c0c2852..125dea1d4fc 100644 --- a/lib/Runtime/Library/TypedArrayIndexEnumerator.h +++ b/lib/Runtime/Library/TypedArrayIndexEnumerator.h @@ -21,5 +21,6 @@ namespace Js TypedArrayIndexEnumerator(TypedArrayBase* typeArrayBase, EnumeratorFlags flags, ScriptContext* scriptContext); virtual JavascriptString * MoveAndGetNext(PropertyId& propertyId, PropertyAttributes* attributes = nullptr) override; virtual void Reset() override; + virtual uint32 GetCurrentItemIndex() override { return index; } }; } diff --git a/lib/Runtime/Types/DynamicObjectPropertyEnumerator.h b/lib/Runtime/Types/DynamicObjectPropertyEnumerator.h index 308e1f55736..adb2259c124 100644 --- a/lib/Runtime/Types/DynamicObjectPropertyEnumerator.h +++ b/lib/Runtime/Types/DynamicObjectPropertyEnumerator.h @@ -46,7 +46,6 @@ namespace Js bool GetSnapShotSemantics() const; bool GetUseCache() const; ScriptContext * GetScriptContext() const { return scriptContext; } - BigPropertyIndex GetInitialPropertyCount() const { return this->initialPropertyCount; } bool Initialize(DynamicObject * object, EnumeratorFlags flags, ScriptContext * requestContext, ForInCache * forInCache); bool IsNullEnumerator() const; diff --git a/lib/Runtime/Types/JavascriptStaticEnumerator.h b/lib/Runtime/Types/JavascriptStaticEnumerator.h index 68fa00d0896..550d26ba528 100644 --- a/lib/Runtime/Types/JavascriptStaticEnumerator.h +++ b/lib/Runtime/Types/JavascriptStaticEnumerator.h @@ -39,7 +39,6 @@ namespace Js void Reset(); uint32 GetCurrentItemIndex(); JavascriptString * MoveAndGetNext(PropertyId& propertyId, PropertyAttributes* attributes = nullptr); - BigPropertyIndex GetInitialPropertyCount() const { return this->propertyEnumerator.GetInitialPropertyCount(); } static uint32 GetOffsetOfCurrentEnumerator() { return offsetof(JavascriptStaticEnumerator, currentEnumerator); } static uint32 GetOffsetOfPrefixEnumerator() { return offsetof(JavascriptStaticEnumerator, prefixEnumerator); }