ソースを参照

With equivalent obj type spec on by default, certain operations still require monomorphic type checks. We've handled this in the dead store pass by locating any equivalent type check that protects an operation that requires a specific type and changing it to use a monomorphic check. But because of the vagaries of inline cache sharing, the operation that does the check may not appear to be monomorphic. Deal with this by having the dead store pass indicate the required type on the checking instruction.

Paul Leathers 10 年 前
コミット
9b49b23fa6

+ 13 - 6
lib/Backend/BackwardPass.cpp

@@ -1069,10 +1069,17 @@ BackwardPass::MergeGuardedProperties(ObjTypeGuardBucket bucket1, ObjTypeGuardBuc
 
     ObjTypeGuardBucket bucket;
     bucket.SetGuardedPropertyOps(mergedPropertyOps);
-    if (bucket1.NeedsMonoCheck() || bucket2.NeedsMonoCheck())
+    Js::Type *monoGuardType = bucket1.GetMonoGuardType();
+    if (monoGuardType != nullptr)
     {
-        bucket.SetNeedsMonoCheck(true);
+        Assert(!bucket2.NeedsMonoCheck() || monoGuardType == bucket2.GetMonoGuardType());
     }
+    else
+    {
+        monoGuardType = bucket2.GetMonoGuardType();
+    }
+    bucket.SetMonoGuardType(monoGuardType);
+
     return bucket;
 }
 
@@ -3988,7 +3995,8 @@ BackwardPass::TrackObjTypeSpecProperties(IR::PropertySymOpnd *opnd, BasicBlock *
         if (opnd->NeedsMonoCheck())
         {
             Assert(opnd->IsMono());
-            bucket->SetNeedsMonoCheck(true);
+            Js::Type *monoGuardType = opnd->HasInitialType() ? opnd->GetInitialType() : opnd->GetType();
+            bucket->SetMonoGuardType(monoGuardType);
         }
 
         if (opnd->NeedsPrimaryTypeCheck())
@@ -4013,11 +4021,10 @@ BackwardPass::TrackObjTypeSpecProperties(IR::PropertySymOpnd *opnd, BasicBlock *
                 {
                     // Some instr protected by this one requires a monomorphic type check. (E.g., final type opt,
                     // fixed field not loaded from prototype.)
-                    Assert(opnd->IsMono());
-                    opnd->SetMustDoMonoCheck(true);
+                    opnd->SetMonoGuardType(bucket->GetMonoGuardType());
                     this->currentInstr->ChangeEquivalentToMonoTypeCheckBailOut();
                 }
-                bucket->SetNeedsMonoCheck(false);
+                bucket->SetMonoGuardType(nullptr);
             }
 
             bucket->SetGuardedPropertyOps(nullptr);

+ 7 - 6
lib/Backend/FlowGraph.h

@@ -71,12 +71,12 @@ class ObjTypeGuardBucket
 {
 private:
     BVSparse<JitArenaAllocator>* guardedPropertyOps;
-    bool needsMonoCheck;
+    Js::Type *                   monoGuardType;
 
 public:
-    ObjTypeGuardBucket() : guardedPropertyOps(nullptr), needsMonoCheck(false) {}
+    ObjTypeGuardBucket() : guardedPropertyOps(nullptr), monoGuardType(nullptr) {}
 
-    ObjTypeGuardBucket(BVSparse<JitArenaAllocator>* guardedPropertyOps) : needsMonoCheck(false)
+    ObjTypeGuardBucket(BVSparse<JitArenaAllocator>* guardedPropertyOps) : monoGuardType(nullptr)
     {
         this->guardedPropertyOps = (guardedPropertyOps != nullptr ? guardedPropertyOps->CopyNew() : nullptr);
     }
@@ -84,15 +84,16 @@ public:
     void Copy(ObjTypeGuardBucket *pNew) const
     {
         pNew->guardedPropertyOps = this->guardedPropertyOps ? this->guardedPropertyOps->CopyNew() : nullptr;
-        pNew->needsMonoCheck = this->needsMonoCheck;
+        pNew->monoGuardType = this->monoGuardType;
     }
 
     BVSparse<JitArenaAllocator> *GetGuardedPropertyOps() const  { return this->guardedPropertyOps; }
     void SetGuardedPropertyOps(BVSparse<JitArenaAllocator> *guardedPropertyOps) { this->guardedPropertyOps = guardedPropertyOps; }
     void AddToGuardedPropertyOps(uint propertyOpId) { Assert(this->guardedPropertyOps != nullptr); this->guardedPropertyOps->Set(propertyOpId); }
 
-    bool NeedsMonoCheck() const { return this->needsMonoCheck; }
-    void SetNeedsMonoCheck(bool value) { this->needsMonoCheck = value; }
+    bool NeedsMonoCheck() const { return this->monoGuardType != nullptr; }
+    void SetMonoGuardType(Js::Type *type) { this->monoGuardType = type; }
+    Js::Type * GetMonoGuardType() const { return this->monoGuardType; }
 
 #if DBG_DUMP
     void Dump() const;

+ 2 - 1
lib/Backend/Lower.cpp

@@ -6762,7 +6762,8 @@ Lowerer::GenerateCachedTypeCheck(IR::Instr *instrChk, IR::PropertySymOpnd *prope
         (propertySymOpnd->IsPoly() || instrChk->HasTypeCheckBailOut());
     Assert(doEquivTypeCheck || !instrChk->HasEquivalentTypeCheckBailOut());
 
-    Js::Type* type = doEquivTypeCheck ? propertySymOpnd->GetFirstEquivalentType() : propertySymOpnd->GetType();
+    Js::Type* type = propertySymOpnd->MustDoMonoCheck() ? propertySymOpnd->GetMonoGuardType() :
+        doEquivTypeCheck ? propertySymOpnd->GetFirstEquivalentType() : propertySymOpnd->GetType();
 
     Js::PropertyGuard* typeCheckGuard = doEquivTypeCheck ?
         (Js::PropertyGuard*)CreateEquivalentTypeGuardAndLinkToGuardedProperties(type, propertySymOpnd) :

+ 1 - 0
lib/Backend/Opnd.cpp

@@ -715,6 +715,7 @@ PropertySymOpnd::New(PropertySym *propertySym, IRType type, Func *func)
     newOpnd->m_type = type;
     newOpnd->SetObjTypeSpecFldInfo(nullptr);
     newOpnd->finalType = nullptr;
+    newOpnd->monoGuardType = nullptr;
     newOpnd->guardedPropOps = nullptr;
     newOpnd->writeGuards = nullptr;
     newOpnd->objTypeSpecFlags = 0;

+ 9 - 6
lib/Backend/Opnd.h

@@ -506,6 +506,7 @@ private:
     Js::ObjTypeSpecFldInfo* objTypeSpecFldInfo;
 public:
     Js::Type* finalType;
+    Js::Type* monoGuardType;
     BVSparse<JitArenaAllocator>* guardedPropOps;
     BVSparse<JitArenaAllocator>* writeGuards;
     byte m_polyCacheUtil;
@@ -534,7 +535,6 @@ public:
                     bool typeDead: 1;
                     bool typeChecked: 1;
                     bool initialTypeChecked: 1;
-                    bool mustDoMonoCheck: 1;
                     bool typeMismatch: 1;
                     bool writeGuardChecked: 1;
                 };
@@ -667,14 +667,17 @@ public:
 
     bool MustDoMonoCheck() const
     {
-        // Question: does this property access need to do a monomorphic check because of some other access
-        // that this check protects?
-        return this->mustDoMonoCheck;
+        return this->monoGuardType != nullptr;
     }
 
-    void SetMustDoMonoCheck(bool value)
+    Js::Type * GetMonoGuardType() const
     {
-        this->mustDoMonoCheck = value;
+        return this->monoGuardType;
+    }
+
+    void SetMonoGuardType(Js::Type *type)
+    {
+        this->monoGuardType = type;
     }
 
     bool NeedsMonoCheck() const

+ 55 - 0
test/fieldopts/fixedfieldmonocheck.js

@@ -0,0 +1,55 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+function test0() {
+    var GiantPrintArray = [];
+    var obj0 = {};
+    var protoObj0 = {};
+    var protoObj1 = {};
+    var obj2 = {};
+    var protoObj2 = {};
+    var func0 = function () {
+        if ({} instanceof EvalError ^ (parseInt()) * (ary - protoObj2.prop6)) {
+            var uniqobj1 = uniqobj0;
+        } else {
+            protoObj0.prop4 = uic8;
+            ({ b: { n: protoObj1.prop0 } });
+            for (var v0 = 0; v0 < 3; v0++) {
+                protoObj1.prop4 = protoObj1.prop1 === protoObj1 && obj2 === protoObj1.prop6;
+            }
+        }
+        GiantPrintArray.push(protoObj1.prop5);
+    };
+    var func1 = function () {
+        (function () {
+            Math.sin(new func0()) ? -(argMath10 * -921543659 - -1139958822.9) : prop4 = ui16;
+            func0(func0());
+        }(new func0()));
+    };
+    var func3 = function () {
+        var uniqobj6 = { 33: func1((new func0())) };
+    };
+    obj0.method0 = func3;
+    method1 = obj0.method0;
+    var ui16 = new Uint16Array();
+    var uic8 = new Uint8ClampedArray();
+    var VarArr0 = Array();
+    ary = 856134889;
+    protoObj0.prop0 = 194709012;
+    protoObj0.prop1 = -377120002;
+    protoObj0.prop2 = -1996023131.9;
+    protoObj0.prop3 = 114;
+    protoObj1.prop0 = -3;
+    protoObj1.prop1 = -1824894349.9;
+    protoObj1.prop2 = 1469720302881920000;
+    protoObj1.prop3 = -1231853442;
+    protoObj1.prop4 = -563681667;
+    protoObj1.prop5 = 1;
+    protoObj2.prop6 = -7120587829494880000;
+    method1(typeof (--protoObj2.prop6 >= (VarArr0[false ? VarArr0[17] = 'x' : undefined, 17] instanceof (typeof Object == 'function' ? Object : Object))));
+}
+test0();
+
+WScript.Echo('pass');

+ 6 - 0
test/fieldopts/rlexe.xml

@@ -836,4 +836,10 @@
       <compile-flags>-force:fieldhoist -off:inlinegetters -off:fixedmethods</compile-flags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>fixedfieldmonocheck.js</files>
+      <compile-flags>-force:fixdataprops</compile-flags>
+    </default>
+  </test>
 </regress-exe>