瀏覽代碼

Writing to proto can leave the TypeHandler::protoCachesWereInvalidated set, and writing to proto again with the same type on the RHS object can skip proto cache invalidation

Paul Leathers 7 年之前
父節點
當前提交
83071cb171
共有 3 個文件被更改,包括 65 次插入1 次删除
  1. 6 1
      lib/Runtime/Library/JavascriptObject.cpp
  2. 54 0
      test/InlineCaches/MissingProtoInval.js
  3. 5 0
      test/InlineCaches/rlexe.xml

+ 6 - 1
lib/Runtime/Library/JavascriptObject.cpp

@@ -194,7 +194,7 @@ BOOL JavascriptObject::ChangePrototype(RecyclableObject* object, RecyclableObjec
     //      ii. Let nextp be the result of calling the [[GetInheritance]] internal method of p with no arguments.
     //      iii.    ReturnIfAbrupt(nextp).
     //      iv. Let  p be nextp.
-        if (IsPrototypeOfStopAtProxy(object, newPrototype, scriptContext)) // Reject cycle
+    if (IsPrototypeOfStopAtProxy(object, newPrototype, scriptContext)) // Reject cycle
     {
         if (shouldThrow)
         {
@@ -229,6 +229,11 @@ BOOL JavascriptObject::ChangePrototype(RecyclableObject* object, RecyclableObjec
     {
         bool allProtoCachesInvalidated = false;
 
+        JavascriptOperators::MapObjectAndPrototypes<true>(newPrototype, [&](RecyclableObject* obj)
+        {
+            obj->ClearProtoCachesWereInvalidated();
+        });
+
         // Notify old prototypes that they are being removed from a prototype chain. This triggers invalidating protocache, etc.
         JavascriptOperators::MapObjectAndPrototypesUntil<true>(object->GetPrototype(), [&](RecyclableObject* obj)->bool
         {

+ 54 - 0
test/InlineCaches/MissingProtoInval.js

@@ -0,0 +1,54 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+function f1() {
+    var o1 = {},o2 = {};
+    var proto1 = {a:'a',b:'b'},proto2 = {a:'a'};
+    o1.__proto__ = proto1;
+    o2.__proto__ = proto2;
+
+    function a(o) { return o.a; }
+    function b(o) { return o.b; }
+
+    a(o1);
+    a(o2);
+    b(o1);
+    b(o2);
+    proto2.__proto__ = {b:'b'};
+    if (b(o2) !== 'b') {
+        WScript.Echo('fail');
+    }
+}
+
+f1()
+f1();
+
+function f2() {
+    var o1 = {b:'b'},o2 = {b:'b'};
+    var proto1 = {a:'a',b:'b'},proto2 = {a:'a'};
+    o1.__proto__ = proto1;
+    o2.__proto__ = proto2;
+
+    function a(o) { return o.a; }
+    function b(o) { return o.b; }
+
+    a(o1);
+    a(o2);
+
+    delete o1.b;
+    delete o2.b;
+
+    b(o1);
+    b(o2);
+    proto2.__proto__ = {b:'b'};
+    if (b(o2) !== 'b') {
+        WScript.Echo('fail');
+    }
+}
+
+f2();
+f2();
+
+WScript.Echo('pass');

+ 5 - 0
test/InlineCaches/rlexe.xml

@@ -120,6 +120,11 @@
       <files>MissingPropertyCache4.js</files>
     </default>
   </test>
+  <test>
+    <default>
+      <files>MissingProtoInval.js</files>
+    </default>
+  </test>
   <test>
     <default>
       <files>instanceOfCacheCrossRegistration.js</files>