Bug 1341261: [Part 6] Teach the Baseline Inspector about the new CacheIR ops r=tcampbell
authorMatthew Gaudet <mgaudet@mozilla.com>
Fri, 08 Jun 2018 16:46:23 -0400
changeset 486354 b4d6c397f94c7597c4d1dee8386ab0e3dd30d97c
parent 486353 2d21ae32eca79970dd918da9686fb14359b7f5ac
child 486355 c65164fbc41ca83aad3476987c9991c5ca81fc8d
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1341261
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1341261: [Part 6] Teach the Baseline Inspector about the new CacheIR ops r=tcampbell
js/src/jit/BaselineInspector.cpp
js/src/jit/CacheIR.cpp
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/BaselineInspector.h"
 
+#include "mozilla/Array.h"
 #include "mozilla/DebugOnly.h"
 
 #include "jit/BaselineIC.h"
 #include "jit/CacheIRCompiler.h"
 
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/ObjectGroup-inl.h"
@@ -423,56 +424,216 @@ CanUseDoubleCompare(ICStub::Kind kind)
 // Whether a baseline stub kind is suitable for an int32 comparison that
 // converts its operands to int32.
 static bool
 CanUseInt32Compare(ICStub::Kind kind)
 {
     return kind == ICStub::Compare_Int32 || kind == ICStub::Compare_Int32WithBoolean;
 }
 
+// Return the MIRtype corresponding to the guard the reader is pointing
+// to, and ensure that afterwards the reader is pointing to the next op
+// (consume operands).
+//
+// An expected parameter is provided to allow GuardType to check we read
+// the guard from the expected operand in debug builds.
+static bool
+GuardType(CacheIRReader& reader, mozilla::Array<MIRType,2>& guardType)
+{
+    CacheOp op = reader.readOp();
+    uint8_t guardOperand = reader.readByte();
+
+    // We only have two entries for guard types.
+    if (guardOperand > 1)
+        return false;
+
+    // Already assigned this guard a type, fail.
+    if (guardType[guardOperand] != MIRType::None)
+        return false;
+
+    switch (op) {
+        // 0 Skip cases
+        case CacheOp::GuardIsString:
+            guardType[guardOperand] = MIRType::String;
+            break;
+        case CacheOp::GuardIsSymbol:
+            guardType[guardOperand] = MIRType::Symbol;
+            break;
+        case CacheOp::GuardIsNumber:
+            guardType[guardOperand] = MIRType::Double;
+            break;
+        case CacheOp::GuardIsUndefined:
+            guardType[guardOperand] = MIRType::Undefined;
+            break;
+        // 1 skip
+        case CacheOp::GuardIsInt32:
+            guardType[guardOperand] = MIRType::Int32;
+            // Skip over result
+            reader.skip();
+            break;
+        case CacheOp::GuardIsBoolean:
+            guardType[guardOperand] = MIRType::Boolean;
+            // Skip over result
+            reader.skip();
+            break;
+        // Unknown op --
+        default:
+            return false;
+    }
+    return true;
+}
+
+// This code works for all Compare ICs where the pattern is
+//
+//  <Guard LHS/RHS>
+//  <Guard RHS/LHS>
+//  <CompareResult>
+//
+// in other cases (like StrictlyDifferentTypes) it will just
+// return CompareUnknown
+static MCompare::CompareType
+ParseCacheIRStubForCompareType(ICCacheIR_Regular* stub)
+{
+    CacheIRReader reader(stub->stubInfo());
+
+    // Two element array to allow parsing the guards
+    // in whichever order they appear.
+    mozilla::Array<MIRType, 2> guards = { MIRType::None, MIRType::None };
+
+    // Parse out two guards
+    if (!GuardType(reader, guards))
+        return MCompare::Compare_Unknown;
+    if (!GuardType(reader, guards))
+        return MCompare::Compare_Unknown;
+
+    // The lhs and rhs ids are asserted in
+    // CompareIRGenerator::tryAttachStub.
+    MIRType lhs_guard = guards[0];
+    MIRType rhs_guard = guards[1];
+
+    if (lhs_guard == rhs_guard)
+    {
+        if (lhs_guard == MIRType::Int32)
+            return MCompare::Compare_Int32;
+        if (lhs_guard == MIRType::Double)
+            return MCompare::Compare_Double;
+        return MCompare::Compare_Unknown;
+    }
+
+    if ((lhs_guard == MIRType::Int32 && rhs_guard == MIRType::Boolean) ||
+        (lhs_guard == MIRType::Boolean && rhs_guard == MIRType::Int32))
+    {
+        // RHS is converting
+        if (rhs_guard == MIRType::Boolean)
+            return MCompare::Compare_Int32MaybeCoerceRHS;
+
+        return MCompare::Compare_Int32MaybeCoerceLHS;
+    }
+
+    if ((lhs_guard == MIRType::Double && rhs_guard == MIRType::Undefined) ||
+        (lhs_guard == MIRType::Undefined && rhs_guard == MIRType::Double))
+    {
+        // RHS is converting
+        if (rhs_guard == MIRType::Undefined)
+            return MCompare::Compare_DoubleMaybeCoerceRHS;
+
+        return MCompare::Compare_DoubleMaybeCoerceLHS;
+    }
+
+    return MCompare::Compare_Unknown;
+}
+
+static bool
+CoercingCompare(MCompare::CompareType type)
+{
+    //Prefer the coercing types if they exist, otherwise just use first's type.
+    if (type == MCompare::Compare_DoubleMaybeCoerceLHS ||
+        type == MCompare::Compare_DoubleMaybeCoerceRHS ||
+        type == MCompare::Compare_Int32MaybeCoerceLHS  ||
+        type == MCompare::Compare_Int32MaybeCoerceRHS)
+        return true;
+    return false;
+}
+
+static MCompare::CompareType
+CompatibleType(MCompare::CompareType first, MCompare::CompareType second)
+{
+    // Caller should have dealt with this case.
+    MOZ_ASSERT(first != second);
+
+    //Prefer the coercing types if they exist, otherwise just use first's type.
+    if (CoercingCompare(first))
+        return first;
+
+    if (CoercingCompare(second))
+        return second;
+
+    return first;
+}
+
 MCompare::CompareType
 BaselineInspector::expectedCompareType(jsbytecode* pc)
 {
     ICStub* first = monomorphicStub(pc);
     ICStub* second = nullptr;
     if (!first && !dimorphicStub(pc, &first, &second))
         return MCompare::Compare_Unknown;
 
     if (ICStub* fallback = second ? second->next() : first->next()) {
         MOZ_ASSERT(fallback->isFallback());
         if (fallback->toCompare_Fallback()->hadUnoptimizableAccess())
             return MCompare::Compare_Unknown;
     }
 
+    if (first->isCacheIR_Regular() && (!second || second->isCacheIR_Regular())) {
+        MCompare::CompareType first_type = ParseCacheIRStubForCompareType(first->toCacheIR_Regular());
+        if (!second)
+            return first_type;
+
+        MCompare::CompareType second_type = ParseCacheIRStubForCompareType(second->toCacheIR_Regular());
+
+        if (first_type == MCompare::Compare_Unknown || second_type == MCompare::Compare_Unknown)
+            return MCompare::Compare_Unknown;
+
+        if (first_type == second_type)
+            return first_type;
+
+        return CompatibleType(first_type, second_type);
+    }
+
+    // If the first is an Int32 compare and the second stub is compatible
+    //  use either a coercing compare int32 or straight int32 compare.
     if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind()))) {
         ICCompare_Int32WithBoolean* coerce =
             first->isCompare_Int32WithBoolean()
             ? first->toCompare_Int32WithBoolean()
             : ((second && second->isCompare_Int32WithBoolean())
-               ? second->toCompare_Int32WithBoolean()
-               : nullptr);
+                ? second->toCompare_Int32WithBoolean()
+                : nullptr);
         if (coerce) {
             return coerce->lhsIsInt32()
-                   ? MCompare::Compare_Int32MaybeCoerceRHS
-                   : MCompare::Compare_Int32MaybeCoerceLHS;
+                    ? MCompare::Compare_Int32MaybeCoerceRHS
+                    : MCompare::Compare_Int32MaybeCoerceLHS;
         }
-        return MCompare::Compare_Int32;
+    return MCompare::Compare_Int32;
     }
 
+    // If the first is an Int32 compare and the second stub is compatible
+    //  use either a coercing compare int32 or straight int32 compare.
     if (CanUseDoubleCompare(first->kind()) && (!second || CanUseDoubleCompare(second->kind()))) {
         ICCompare_NumberWithUndefined* coerce =
             first->isCompare_NumberWithUndefined()
             ? first->toCompare_NumberWithUndefined()
             : (second && second->isCompare_NumberWithUndefined())
-              ? second->toCompare_NumberWithUndefined()
-              : nullptr;
+            ? second->toCompare_NumberWithUndefined()
+            : nullptr;
         if (coerce) {
             return coerce->lhsIsUndefined()
-                   ? MCompare::Compare_DoubleMaybeCoerceLHS
-                   : MCompare::Compare_DoubleMaybeCoerceRHS;
+                ? MCompare::Compare_DoubleMaybeCoerceLHS
+                : MCompare::Compare_DoubleMaybeCoerceRHS;
         }
         return MCompare::Compare_Double;
     }
 
     return MCompare::Compare_Unknown;
 }
 
 static bool
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -4934,16 +4934,22 @@ CompareIRGenerator::tryAttachStub()
 {
     MOZ_ASSERT(cacheKind_ == CacheKind::Compare);
     MOZ_ASSERT(IsEqualityOp(op_) ||
                op_ == JSOP_LE || op_ == JSOP_LT ||
                op_ == JSOP_GE || op_ == JSOP_GT);
 
     AutoAssertNoPendingException aanpe(cx_);
 
+    constexpr uint8_t lhsIndex = 0;
+    constexpr uint8_t rhsIndex = 1;
+
+    static_assert(lhsIndex == 0 && rhsIndex == 1,
+        "Indexes relied upon by baseline inspector");
+
     ValOperandId lhsId(writer.setInputOperandId(0));
     ValOperandId rhsId(writer.setInputOperandId(1));
 
     if (IsEqualityOp(op_)) {
         if (tryAttachString(lhsId, rhsId))
             return true;
         if (tryAttachObject(lhsId, rhsId))
             return true;