Просмотр исходного кода

[MSFT 16526077] When branching a type path, only copy setter indices that refer to the initialized part of the path. Otherwise, wait for the correct index, which may be different on this branch of the path, to be set when the setter property is added to the handler.

Paul Leathers 8 лет назад
Родитель
Сommit
4fda0bd193

+ 12 - 4
lib/Runtime/Types/PathTypeHandler.cpp

@@ -1135,11 +1135,11 @@ namespace Js
             _Analysis_assume_(setters != nullptr);
             setterSlot = setters[propertyIndex];
         }
-        else if (attributes != nullptr)
+        else
         {
             // We may already have a valid setter slot, if the property has gone from accessor to data and now back to accessor.
             // Re-use the setter slot if we can.
-            setters = newTypeHandler->GetSetterSlots();
+            setters = PathTypeHandlerWithAttr::FromPathTypeHandler(newTypeHandler)->PathTypeHandlerWithAttr::GetSetterSlots();
             if (setters != nullptr)
             {
                 setterSlot = setters[propertyIndex];
@@ -1160,7 +1160,7 @@ namespace Js
                 instance->ReplaceType(newType);
             }
             newTypeHandler = PathTypeHandlerBase::FromTypeHandler(newType->GetTypeHandler());
-            setters = newTypeHandler->GetSetterSlots();
+            setters = PathTypeHandlerWithAttr::FromPathTypeHandler(newTypeHandler)->PathTypeHandlerWithAttr::GetSetterSlots();
             Assert(setters != nullptr);
             _Analysis_assume_(setters != nullptr);
             setters[propertyIndex] = setterSlot;
@@ -2188,9 +2188,17 @@ namespace Js
         }
         else
         {
+            uint16 pathLength = GetPathLength();
             // In branching cases, the new type path may be shorter than the old.
             initStart = min(newTypePathSize, oldPathSize);
-            memcpy(newSetters, oldSetters, sizeof(PathTypeSetterSlotIndex) * initStart);
+            for (uint8 i = 0; i < initStart; i++)
+            {
+                // Only copy setter indices that refer to the part of the path contained by this handler already.
+                // Otherwise, wait for the correct index, which may be different on this path of the branch,
+                // to be set when the setter property is added to the handler.
+                PathTypeSetterSlotIndex oldIndex = oldSetters[i];
+                newSetters[i] = oldIndex < pathLength ? oldIndex : NoSetterSlot;
+            }
         }
         for (uint8 i = initStart; i < newTypePathSize; i++)
         {

+ 17 - 0
lib/Runtime/Types/PathTypeHandler.h

@@ -174,6 +174,9 @@ namespace Js
         virtual DynamicTypeHandler* ConvertToTypeWithItemAttributes(DynamicObject* instance) override;
         virtual BOOL AllPropertiesAreEnumerable() override { return true; }
         virtual BOOL IsPathTypeHandler() const { return TRUE; }
+#if DBG
+        virtual bool IsPathTypeHandlerWithAttr() const { return false; }
+#endif
 
         virtual void ShrinkSlotAndInlineSlotCapacity() override;
         virtual void LockInlineSlotCapacity() override;
@@ -434,6 +437,8 @@ namespace Js
 
     class PathTypeHandlerNoAttr : public PathTypeHandlerBase
     {
+        friend class PathTypeHandlerBase;
+
     public:
         DEFINE_GETCPPNAME();
 
@@ -450,6 +455,8 @@ namespace Js
 
     class PathTypeHandlerWithAttr : public PathTypeHandlerNoAttr
     {
+        friend class PathTypeHandlerBase;
+
     private:
         Field(ObjectSlotAttributes *) attributes;
         Field(PathTypeSetterSlotIndex *) setters;
@@ -479,6 +486,16 @@ namespace Js
         static PathTypeHandlerWithAttr * New(ScriptContext * scriptContext, TypePath * typePath, ObjectSlotAttributes * attributes, PathTypeSetterSlotIndex * setters, PathTypeSetterSlotIndex setterCount, uint16 pathLength, const PropertyIndex slotCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots, bool isLocked = false, bool isShared = false, DynamicType* predecessorType = nullptr);
         static PathTypeHandlerWithAttr * New(ScriptContext * scriptContext, PathTypeHandlerWithAttr * typeHandler, bool isLocked, bool isShared);
 
+        static PathTypeHandlerWithAttr * FromPathTypeHandler(PathTypeHandlerBase * typeHandler)
+        {
+            Assert(typeHandler->IsPathTypeHandlerWithAttr());
+            return static_cast<PathTypeHandlerWithAttr*>(typeHandler);
+        }
+
+#if DBG
+        virtual bool IsPathTypeHandlerWithAttr() const override { return true; }
+#endif
+
         virtual BOOL IsEnumerable(DynamicObject* instance, PropertyId propertyId) override;
         virtual BOOL IsWritable(DynamicObject* instance, PropertyId propertyId) override;
         virtual BOOL IsConfigurable(DynamicObject* instance, PropertyId propertyId) override;

+ 11 - 1
test/es5/objlitgetset2.js

@@ -33,4 +33,14 @@ function __getRandomProperty(obj, seed) {
       __v_13862.p = 0;
       if (__v_13862.q !== 0) WScript.Echo(__v_13862.q);
   })();
-  __v_13851[__getRandomProperty(__v_13851, 483779)] = __getRandomObject();
+  __v_13851[__getRandomProperty(__v_13851, 483779)] = __getRandomObject();
+
+let o = {get a(){},x:0};
+if (o.x !== 0) WScript.Echo('fail x0');
+Object.defineProperty(o, 'x', {configurable:true,enumerable:true,get:function(){return 'x1'}});
+if (o.x !== 'x1') WScript.Echo('fail x1');
+let p = {get a(){},x:0};
+p.y = 'y';
+Object.defineProperty(p, 'x', {configurable:true,enumerable:true,get:function(){return 'x2'}});
+if (p.x !== 'x2') WScript.Echo('fail x2');
+if (p.y !== 'y') WScript.Echo('fail y');