diff --git a/lib/Common/ConfigFlagsList.h b/lib/Common/ConfigFlagsList.h index 65774daacc7..7886e60359b 100644 --- a/lib/Common/ConfigFlagsList.h +++ b/lib/Common/ConfigFlagsList.h @@ -384,6 +384,7 @@ PHASE(All) PHASE(TypePathDynamicSize) PHASE(ObjectCopy) PHASE(ShareTypesWithAttributes) + PHASE(ShareTypesWithDeleted) PHASE(ShareAccessorTypes) PHASE(ShareFuncTypes) PHASE(ConditionalCompilation) diff --git a/lib/Runtime/Language/JavascriptOperators.cpp b/lib/Runtime/Language/JavascriptOperators.cpp index 5ac8005e367..ec662a50c52 100644 --- a/lib/Runtime/Language/JavascriptOperators.cpp +++ b/lib/Runtime/Language/JavascriptOperators.cpp @@ -1699,6 +1699,10 @@ using namespace Js; template BOOL JavascriptOperators::GetProperty_Internal(Var instance, RecyclableObject* propertyObject, const bool isRoot, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info) { +#if ENABLE_FIXED_FIELDS && DBG + DynamicTypeHandler *dynamicTypeHandler = nullptr; +#endif + if (TaggedNumber::Is(instance)) { PropertyValueInfo::ClearCacheInfo(info); @@ -1721,6 +1725,9 @@ using namespace Js; } else { +#if ENABLE_FIXED_FIELDS && DBG + dynamicTypeHandler = VarIs(object) ? VarTo(object)->GetTypeHandler() : nullptr; +#endif PropertyQueryFlags result = object->GetPropertyQuery(instance, propertyId, value, info, requestContext); if (result != PropertyQueryFlags::Property_NotFound) { @@ -1740,10 +1747,10 @@ using namespace Js; if (foundProperty) { #if ENABLE_FIXED_FIELDS && DBG - if (DynamicObject::IsBaseDynamicObject(object)) + // Note: It's valid to check this for the original type handler but not for a new type handler that may have been installed + // by a getter that, for instance, deleted and re-added the property. + if (dynamicTypeHandler) { - DynamicObject* dynamicObject = (DynamicObject*)object; - DynamicTypeHandler* dynamicTypeHandler = dynamicObject->GetDynamicType()->GetTypeHandler(); Var property; if (dynamicTypeHandler->CheckFixedProperty(requestContext->GetPropertyName(propertyId), &property, requestContext)) { @@ -8846,23 +8853,18 @@ using namespace Js; // ES5 8.12.9.9.c: Convert the property named P of object O from an accessor property to a data property. // Preserve the existing values of the converted property's [[Configurable]] and [[Enumerable]] attributes // and set the rest of the property's attributes to their default values. - // Note: avoid using SetProperty/SetPropertyWithAttributes here because they has undesired side-effects: - // it calls previous setter and in some cases of attribute values throws. - // To walk around, call DeleteProperty and then AddProperty. PropertyAttributes preserveFromObject = currentDescriptor->GetAttributes() & (PropertyConfigurable | PropertyEnumerable); tempDescriptor.SetAttributes(preserveFromObject, PropertyConfigurable | PropertyEnumerable); tempDescriptor.MergeFrom(descriptor); // Update only fields specified in 'descriptor'. Var descriptorValue = descriptor.ValueSpecified() ? descriptor.GetValue() : defaultDataValue; - // Note: HostDispath'es implementation of DeleteProperty currently throws E_NOTIMPL. - obj->DeleteProperty(propId, PropertyOperation_None); - BOOL tempResult = obj->SetPropertyWithAttributes(propId, descriptorValue, tempDescriptor.GetAttributes(), NULL, PropertyOperation_Force); - Assert(tempResult); + BOOL result = VarTo(obj)->ConvertAccessorToData(propId, descriptorValue, tempDescriptor.GetAttributes()); // At this time we already set value and attributes to desired values, // thus we can skip step ES5 8.12.9.12 and simply return true. - return TRUE; + Assert(result); + return result; } } } diff --git a/lib/Runtime/RuntimeCommon.h b/lib/Runtime/RuntimeCommon.h index 484953244a8..3530811f1c2 100644 --- a/lib/Runtime/RuntimeCommon.h +++ b/lib/Runtime/RuntimeCommon.h @@ -84,6 +84,7 @@ namespace Js ObjectSlotAttr_Int = 0x20, ObjectSlotAttr_Double = 0x40, ObjectSlotAttr_Default = (ObjectSlotAttr_Writable|ObjectSlotAttr_Enumerable|ObjectSlotAttr_Configurable), + ObjectSlotAttr_DeletedDefault = (ObjectSlotAttr_Deleted|ObjectSlotAttr_Writable|ObjectSlotAttr_Configurable), ObjectSlotAttr_PropertyAttributesMask = (ObjectSlotAttr_Default|ObjectSlotAttr_Deleted), ObjectSlotAttr_All = 0xFF, ObjectSlotAttr_Setter = ObjectSlotAttr_All ^ ObjectSlotAttr_Deleted, // an impossible value indicating "setter" diff --git a/lib/Runtime/Types/DynamicObject.cpp b/lib/Runtime/Types/DynamicObject.cpp index 012b23d8e43..f729bcab11d 100644 --- a/lib/Runtime/Types/DynamicObject.cpp +++ b/lib/Runtime/Types/DynamicObject.cpp @@ -383,6 +383,19 @@ namespace Js this->type = predecessorType; } + BOOL DynamicObject::ConvertAccessorToData(PropertyId propId, Var value, PropertyAttributes attributes) + { + uint32 indexVal; + if (GetScriptContext()->IsNumericPropertyId(propId, &indexVal)) + { + DeleteItem(indexVal, PropertyOperation_None); + } + GetTypeHandler()->InitProperty(this, propId, value, PropertyOperation_Force, nullptr); + BOOL result = SetPropertyWithAttributes(propId, value, attributes, NULL, PropertyOperation_Force); + Assert(result); + return result; + } + DWORD DynamicObject::GetOffsetOfAuxSlots() { return offsetof(DynamicObject, auxSlots); diff --git a/lib/Runtime/Types/DynamicObject.h b/lib/Runtime/Types/DynamicObject.h index f25585644ca..44465cb9015 100644 --- a/lib/Runtime/Types/DynamicObject.h +++ b/lib/Runtime/Types/DynamicObject.h @@ -317,6 +317,8 @@ namespace Js void ChangeTypeIf(const Type* oldType); + BOOL ConvertAccessorToData(PropertyId propId, Var value, PropertyAttributes attributes); + BOOL FindNextProperty(BigPropertyIndex& index, JavascriptString** propertyString, PropertyId* propertyId, PropertyAttributes* attributes, DynamicType *typeToEnumerate, EnumeratorFlags flags, ScriptContext * requestContext, PropertyValueInfo * info); diff --git a/lib/Runtime/Types/PathTypeHandler.cpp b/lib/Runtime/Types/PathTypeHandler.cpp index f48bf8e3cb0..f6040e1861f 100644 --- a/lib/Runtime/Types/PathTypeHandler.cpp +++ b/lib/Runtime/Types/PathTypeHandler.cpp @@ -123,7 +123,7 @@ namespace Js PathTypeSingleSuccessorInfo::PathTypeSingleSuccessorInfo(const PathTypeSuccessorKey key, RecyclerWeakReference * typeWeakRef) : successorKey(key), successorTypeWeakRef(typeWeakRef) { - Assert(key.HasInfo()); + Assert(key.HasInfo() || (key.GetAttributes() & ObjectSlotAttr_Deleted)); Assert(typeWeakRef != nullptr); this->kind = PathTypeSuccessorKindSingle; } @@ -331,7 +331,8 @@ namespace Js for (; index < GetPathLength(); ++index) { ObjectSlotAttributes attr = objectAttrs ? objectAttrs[index] : ObjectSlotAttr_Default; - if( !(attr & ObjectSlotAttr_Deleted) && attr != ObjectSlotAttr_Setter && (!!(flags & EnumeratorFlags::EnumNonEnumerable) || (attr & ObjectSlotAttr_Enumerable))) + if(!(attr & ObjectSlotAttr_Deleted) && attr != ObjectSlotAttr_Setter && + (!!(flags & EnumeratorFlags::EnumNonEnumerable) || (attr & ObjectSlotAttr_Enumerable))) { const PropertyRecord* propertyRecord = GetTypePath()->GetPropertyId(index); @@ -369,25 +370,41 @@ namespace Js // Need to enumerate a different type than the current one. This is because type snapshot enumerate is enabled and the // object's type changed since enumeration began, so need to enumerate properties of the initial type. DynamicTypeHandler *const typeHandlerToEnumerate = typeToEnumerate->GetTypeHandler(); - - if (!typeHandlerToEnumerate->IsPathTypeHandler()) - { - return typeHandlerToEnumerate->FindNextProperty(scriptContext, index, propertyStringName, propertyId, attributes, type, typeToEnumerate, flags, instance, info); - } - - PathTypeHandlerBase* pathTypeToEnumerate = (PathTypeHandlerBase*)typeHandlerToEnumerate; - - BOOL found = pathTypeToEnumerate->FindNextProperty(scriptContext, index, propertyStringName, propertyId, attributes, typeToEnumerate, typeToEnumerate, flags, instance, info); - - // We got a property from previous type, but this property may have been deleted - if (found == TRUE && this->GetPropertyIndex(*propertyId) == Js::Constants::NoSlot) - { - PropertyValueInfo::SetNoCache(info, instance); - return FALSE; + for( + ; + typeHandlerToEnumerate->FindNextProperty( + scriptContext, + index, + propertyStringName, + propertyId, + attributes, + typeToEnumerate, + typeToEnumerate, + flags, + instance, + info); + ++index) + { + PropertyIndex tmpIndex = this->GetPropertyIndex(*propertyId); + if (tmpIndex != Constants::NoSlot) + { + ObjectSlotAttributes attr = objectAttrs ? objectAttrs[tmpIndex] : ObjectSlotAttr_Default; + if (!(attr & ObjectSlotAttr_Deleted) && attr != ObjectSlotAttr_Setter && + (!!(flags & EnumeratorFlags::EnumNonEnumerable) || (attr & ObjectSlotAttr_Enumerable))) + { + if (attributes) + { + *attributes = ObjectSlotAttributesToPropertyAttributes(attr); + } + + PropertyValueInfo::SetNoCache(info, instance); + return TRUE; + } + } } PropertyValueInfo::SetNoCache(info, instance); - return found; + return FALSE; } BOOL PathTypeHandlerBase::SetAttributesHelper(DynamicObject* instance, PropertyId propertyId, PropertyIndex propertyIndex, ObjectSlotAttributes * instanceAttributes, ObjectSlotAttributes propertyAttributes, bool setAllAttributes) @@ -445,13 +462,13 @@ namespace Js PropertyIndex pathLength = GetPathLength(); PropertyIndex currentSlotIndex = propertyIndex; ObjectSlotAttributes currentAttributes = propertyAttributes; + PropertyId currentPropertyId = (currentAttributes & ObjectSlotAttr_Deleted) ? Constants::NoProperty : propertyId; PathTypeHandlerBase *currentTypeHandler = predTypeHandler; ScriptContext *scriptContext = instance->GetScriptContext(); while (true) { - const PropertyRecord *currentPropertyRecord = GetTypePath()->GetPropertyIdUnchecked(currentSlotIndex); PropertyIndex index; - currentType = currentTypeHandler->PromoteType(currentType, PathTypeSuccessorKey(currentPropertyRecord->GetPropertyId(), currentAttributes), false, scriptContext, instance, &index); + currentType = currentTypeHandler->PromoteType(currentType, PathTypeSuccessorKey(currentPropertyId, currentAttributes), false, scriptContext, instance, &index); currentTypeHandler = PathTypeHandlerBase::FromTypeHandler(currentType->GetTypeHandler()); #if ENABLE_FIXED_FIELDS #ifdef SUPPORT_FIXED_FIELDS_ON_PATH_TYPES @@ -461,9 +478,9 @@ namespace Js #endif if (currentAttributes == ObjectSlotAttr_Setter) { - PropertyIndex getterIndex = currentTypeHandler->GetPropertyIndex(currentPropertyRecord->GetPropertyId()); - Assert(getterIndex != Constants::NoSlot); - if (currentTypeHandler->GetAttributes(getterIndex) & ObjectSlotAttr_Accessor) + Assert(currentPropertyId != Constants::NoProperty); + PropertyIndex getterIndex = currentTypeHandler->GetPropertyIndex(currentPropertyId); + if (getterIndex != Constants::NoSlot && currentTypeHandler->GetAttributes(getterIndex) & ObjectSlotAttr_Accessor) { currentTypeHandler->SetSetterSlot(getterIndex, (PathTypeSetterSlotIndex)currentSlotIndex); } @@ -474,6 +491,15 @@ namespace Js break; } currentAttributes = instanceAttributes ? instanceAttributes[currentSlotIndex] : ObjectSlotAttr_Default; + Assert(GetTypePath()->GetPropertyIdUnchecked(currentSlotIndex) || (currentAttributes & ObjectSlotAttr_Deleted)); + if (currentAttributes & ObjectSlotAttr_Deleted) + { + currentPropertyId = Constants::NoProperty; + } + else + { + currentPropertyId = GetTypePath()->GetPropertyIdUnchecked(currentSlotIndex)->GetPropertyId(); + } } Assert(currentType != instance->GetType()); @@ -969,16 +995,21 @@ namespace Js return TRUE; } - ObjectSlotAttributes attr = this->GetAttributes(index); - if (attr & ObjectSlotAttr_Deleted) - { - return TRUE; - } - if (!(attr & ObjectSlotAttr_Configurable)) + ObjectSlotAttributes *attributes = this->GetAttributeArray(); + ObjectSlotAttributes attr = ObjectSlotAttr_Default; + if (attributes) { - JavascriptError::ThrowCantDeleteIfStrictModeOrNonconfigurable( - flags, scriptContext, scriptContext->GetPropertyName(propertyId)->GetBuffer()); - return FALSE; + attr = attributes[index]; + if (attr & ObjectSlotAttr_Deleted) + { + return TRUE; + } + if (!(attr & ObjectSlotAttr_Configurable)) + { + JavascriptError::ThrowCantDeleteIfStrictModeOrNonconfigurable( + flags, scriptContext, scriptContext->GetPropertyName(propertyId)->GetBuffer()); + return FALSE; + } } uint16 pathLength = GetPathLength(); @@ -990,14 +1021,37 @@ namespace Js return TRUE; } + if (PHASE_OFF1(ShareTypesWithDeletedPhase) || PHASE_OFF1(ShareTypesWithAttributesPhase)) + { #ifdef PROFILE_TYPES - instance->GetScriptContext()->convertPathToDictionaryDeletedCount++; + instance->GetScriptContext()->convertPathToDictionaryDeletedCount++; #endif - BOOL deleteResult = TryConvertToSimpleDictionaryType(instance, pathLength)->DeleteProperty(instance, propertyId, flags); + return TryConvertToSimpleDictionaryType(instance, pathLength)->DeleteProperty(instance, propertyId, flags); + } + + Var undef = scriptContext->GetLibrary()->GetUndefined(); + SetSlotUnchecked(instance, index, undef); + if (attr & ObjectSlotAttr_Accessor) + { + PathTypeSetterSlotIndex setter = PathTypeHandlerWithAttr::FromPathTypeHandler(this)->PathTypeHandlerWithAttr::GetSetterSlotIndex(index); + Assert(setter < this->GetPathLength()); + SetSlotUnchecked(instance, setter, undef); + } - AssertMsg(deleteResult, "PathType delete property can return false, this should be handled in DeleteLastProperty as well."); + BOOL result = SetAttributesHelper(instance, propertyId, index, attributes, ObjectSlotAttr_DeletedDefault, true); + if (!result) + { + return instance->GetTypeHandler()->DeleteProperty(instance, propertyId, flags); + } - return deleteResult; +#if ENABLE_FIXED_FIELDS +#ifdef SUPPORT_FIXED_FIELDS_ON_PATH_TYPES + PathTypeHandlerBase *newTypeHandler = PathTypeHandlerBase::FromTypeHandler(instance->GetTypeHandler()); + newTypeHandler->InvalidateFixedFieldAt(propertyId, index, scriptContext); +#endif +#endif + + return TRUE; } BOOL PathTypeHandlerBase::IsEnumerable(DynamicObject* instance, PropertyId propertyId) @@ -1501,6 +1555,11 @@ namespace Js for (PropertyIndex i = 0; i < oldTypeHandler->GetPathLength(); i++) { ObjectSlotAttributes attr = attributes ? attributes[i] : ObjectSlotAttr_Default; + if (attr & ObjectSlotAttr_Deleted) + { + ::Math::PostInc(newTypeHandler->nextPropertyIndex); + continue; + } const PropertyRecord * propertyRecord = typePath->GetPropertyId(i); if (attr == ObjectSlotAttr_Setter) { @@ -1508,8 +1567,7 @@ namespace Js // the setter to get the next free slot. DictionaryPropertyDescriptor *descriptor; bool result = newTypeHandler->propertyMap->TryGetReference(propertyRecord, &descriptor); - Assert(result); - if (!(attributes[descriptor->GetDataPropertyIndex()] & ObjectSlotAttr_Accessor)) + if (!result || !(attributes[descriptor->GetDataPropertyIndex()] & ObjectSlotAttr_Accessor)) { // Setter without a getter; this is a stale entry, so ignore it // Just consume the slot so no descriptor refers to it. @@ -1755,6 +1813,12 @@ namespace Js ObjectSlotAttributes * attributes = this->GetAttributeArray(); for (PropertyIndex i = 0; i < oldTypeHandler->GetPathLength(); i++) { + ObjectSlotAttributes attr = attributes ? attributes[i] : ObjectSlotAttr_Default; + if (attr & ObjectSlotAttr_Deleted) + { + ::Math::PostInc(newTypeHandler->nextPropertyIndex); + continue; + } #if ENABLE_FIXED_FIELDS if (PathTypeHandlerBase::FixPropsOnPathTypes()) { @@ -2021,7 +2085,7 @@ namespace Js { // We need to branch the type path. - if (oldSetters) + if (oldAttributes) { newTypePath = GetTypePath()->Branch(recycler, GetPathLength(), GetIsOrMayBecomeShared() && !IsolatePrototypes(), oldAttributes); } @@ -2112,7 +2176,8 @@ namespace Js } bool isSetterProperty = key.GetAttributes() == ObjectSlotAttr_Setter; - if (isSetterProperty) + bool isDeadSlot = isSetterProperty || (key.GetAttributes() & ObjectSlotAttr_Deleted); + if (isDeadSlot) { // Not actually adding a property ID to the type path map here. index = (PropertyIndex)newTypePath->AddInternal(propertyRecord); @@ -2214,7 +2279,7 @@ namespace Js nextPath = (PathTypeHandlerBase *)nextType->GetTypeHandler(); Assert(nextPath->GetIsInlineSlotCapacityLocked() == this->GetIsInlineSlotCapacityLocked()); - index = nextPath->GetPropertyIndex(propertyRecord); + index = this->GetPathLength(); #if ENABLE_FIXED_FIELDS Assert((FixPropsOnPathTypes() && nextPath->GetMayBecomeShared()) || (nextPath->GetIsShared() && nextType->GetIsShared())); @@ -2222,7 +2287,11 @@ namespace Js { if (!nextPath->GetIsShared()) { - nextPath->AddBlankFieldAt(propertyRecord->GetPropertyId(), index, scriptContext); + if (!(key.GetAttributes() & ObjectSlotAttr_Deleted) && key.GetAttributes() != ObjectSlotAttr_Setter) + { + Assert(index == nextPath->GetPropertyIndex(propertyRecord)); + nextPath->AddBlankFieldAt(propertyRecord->GetPropertyId(), index, scriptContext); + } nextPath->DoShareTypeHandlerInternal(scriptContext); } nextType->ShareType(); @@ -3442,7 +3511,12 @@ namespace Js TTD::NSSnapType::SnapEntryDataKindTag tag; if (attr == ObjectSlotAttr_Setter) { - attr = attributes[GetTypePath()->LookupInline(propertyId, GetPathLength())]; + PropertyIndex getterIndex = GetTypePath()->LookupInline(propertyId, GetPathLength()); + if (getterIndex == Constants::NoSlot) + { + continue; + } + attr = attributes[index]; tag = TTD::NSSnapType::SnapEntryDataKindTag::Setter; } else if (attr & ObjectSlotAttr_Accessor) @@ -3709,6 +3783,30 @@ namespace Js return GetPropertyCount() - setterCount; } + PropertyId PathTypeHandlerWithAttr::GetPropertyId(ScriptContext* scriptContext, PropertyIndex index) + { + if (index < GetPathLength() && !(attributes[index] & ObjectSlotAttr_Deleted)) + { + return GetTypePath()->GetPropertyId(index)->GetPropertyId(); + } + else + { + return Constants::NoProperty; + } + } + + PropertyId PathTypeHandlerWithAttr::GetPropertyId(ScriptContext* scriptContext, BigPropertyIndex index) + { + if (index < GetPathLength() && !(attributes[index] & ObjectSlotAttr_Deleted)) + { + return GetTypePath()->GetPropertyId(index)->GetPropertyId(); + } + else + { + return Constants::NoProperty; + } + } + BOOL PathTypeHandlerWithAttr::HasProperty(DynamicObject* instance, PropertyId propertyId, __out_opt bool *noRedecl, _Inout_opt_ PropertyValueInfo* info) { if (noRedecl != nullptr) diff --git a/lib/Runtime/Types/PathTypeHandler.h b/lib/Runtime/Types/PathTypeHandler.h index 1d1b2d92ab7..8e99fc38a8e 100644 --- a/lib/Runtime/Types/PathTypeHandler.h +++ b/lib/Runtime/Types/PathTypeHandler.h @@ -506,6 +506,9 @@ namespace Js virtual BOOL SetWritable(DynamicObject* instance, PropertyId propertyId, BOOL value) override; virtual BOOL SetConfigurable(DynamicObject* instance, PropertyId propertyId, BOOL value) override; + virtual PropertyId GetPropertyId(ScriptContext* scriptContext, PropertyIndex index) override; + virtual PropertyId GetPropertyId(ScriptContext* scriptContext, BigPropertyIndex index) override; + virtual int GetPropertyCountForEnum() override; virtual BOOL HasProperty(DynamicObject* instance, PropertyId propertyId, __out_opt bool *noRedecl, _Inout_opt_ PropertyValueInfo* info) override; virtual BOOL GetProperty(DynamicObject* instance, Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override; diff --git a/lib/Runtime/Types/TypePath.h b/lib/Runtime/Types/TypePath.h index e86062fac12..83199ce44cd 100644 --- a/lib/Runtime/Types/TypePath.h +++ b/lib/Runtime/Types/TypePath.h @@ -208,7 +208,7 @@ namespace Js for (PropertyIndex i = 0; i < pathLength; i++) { - if (checkAttributes && attributes[i] == ObjectSlotAttr_Setter) + if (checkAttributes && (attributes[i] == ObjectSlotAttr_Setter || (attributes[i] & ObjectSlotAttr_Deleted))) { branchedPath->AddInternal(assignments[i]); } diff --git a/test/Basics/DeleteProperty1.baseline b/test/Basics/DeleteProperty1.baseline index 94b22537b2a..5efe8532755 100644 --- a/test/Basics/DeleteProperty1.baseline +++ b/test/Basics/DeleteProperty1.baseline @@ -4,7 +4,7 @@ c = 20 a = 0 c = 20 a = 0 -b = 23 c = 20 +b = 23 a = 0 c = 20 diff --git a/test/JSON/toJSON.js b/test/JSON/toJSON.js index 731c4834d3c..f10a39caf9d 100644 --- a/test/JSON/toJSON.js +++ b/test/JSON/toJSON.js @@ -51,13 +51,13 @@ fnc.prototype.toJSON = function() { TEST('{"a":1,"b":2}', JSON.stringify(obj));; Object.defineProperty(obj, "c", { get: () => 3, enumerable: true }); obj.d = 4; - TEST('{"c":3,"a":1,"b":2,"d":4}', JSON.stringify(obj)); + TEST('{"a":1,"b":2,"c":3,"d":4}', JSON.stringify(obj)); obj[9]=19; - TEST('{"9":19,"c":3,"a":1,"b":2,"d":4}', JSON.stringify(obj)); + TEST('{"9":19,"a":1,"b":2,"c":3,"d":4}', JSON.stringify(obj)); delete obj[9] - TEST('{"c":3,"a":1,"b":2,"d":4}', JSON.stringify(obj)); + TEST('{"a":1,"b":2,"c":3,"d":4}', JSON.stringify(obj)); delete obj['a'] - TEST('{"c":3,"b":2,"d":4}', JSON.stringify(obj)); + TEST('{"b":2,"c":3,"d":4}', JSON.stringify(obj)); } // test getter diff --git a/test/Object/TypeSnapshotEnumeration.baseline b/test/Object/TypeSnapshotEnumeration.baseline index f61ce3affcb..7b2b0bb069f 100644 --- a/test/Object/TypeSnapshotEnumeration.baseline +++ b/test/Object/TypeSnapshotEnumeration.baseline @@ -48,7 +48,7 @@ test2(DeferredTypeObject): [] test3(PathTypeObject): [p] test3(SimpleDictionaryTypeObject): [p] -test3(DictionaryTypeObject): [p, q] +test3(DictionaryTypeObject): [p] test3(Array): [0, 1, p] test3(Es5Array): [0, 1, p, q] test3(Arguments): [0, p] @@ -56,7 +56,7 @@ test3(DeferredTypeObject): [] test3(PathTypeObject): [p] test3(SimpleDictionaryTypeObject): [p] -test3(DictionaryTypeObject): [p, q] +test3(DictionaryTypeObject): [p] test3(Array): [0, 1, p] test3(Es5Array): [0, 1, p, q] test3(Arguments): [0, p] @@ -128,7 +128,7 @@ test7(DeferredTypeObject): [] test8(PathTypeObject): [p] test8(SimpleDictionaryTypeObject): [p] -test8(DictionaryTypeObject): [p, q] +test8(DictionaryTypeObject): [p] test8(Array): [0, 1, p] test8(Es5Array): [0, 1, p, q] test8(Arguments): [0, p] @@ -136,7 +136,7 @@ test8(DeferredTypeObject): [] test8(PathTypeObject): [p] test8(SimpleDictionaryTypeObject): [p] -test8(DictionaryTypeObject): [p, q] +test8(DictionaryTypeObject): [p] test8(Array): [0, 1, p] test8(Es5Array): [0, 1, p, q] test8(Arguments): [0, p] diff --git a/test/Object/assign.baseline b/test/Object/assign.baseline index ecc00f6c36e..e4d5cf46392 100644 --- a/test/Object/assign.baseline +++ b/test/Object/assign.baseline @@ -1,5 +1,5 @@ ObjectCopy succeeded -ObjectCopy: Can't copy: Don't have PathTypeHandler +ObjectCopy: Can't copy: from obj has non-enumerable properties ObjectCopy: Can't copy: type handler has accessors ObjectCopy: Can't copy: type handler has accessors ObjectCopy: Can't copy: Prototypes don't match