DFGExitProfile.h
1 /* 2 * Copyright (C) 2011-2019 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #pragma once 27 28 #if ENABLE(DFG_JIT) 29 30 #include "ConcurrentJSLock.h" 31 #include "ExitKind.h" 32 #include "ExitingInlineKind.h" 33 #include "ExitingJITType.h" 34 #include <wtf/HashSet.h> 35 #include <wtf/Vector.h> 36 37 namespace JSC { namespace DFG { 38 39 class FrequentExitSite { 40 public: 41 FrequentExitSite() 42 : m_bytecodeIndex(BytecodeIndex(0)) 43 , m_kind(ExitKindUnset) 44 , m_jitType(ExitFromAnything) 45 , m_inlineKind(ExitFromAnyInlineKind) 46 { 47 } 48 49 FrequentExitSite(WTF::HashTableDeletedValueType) 50 : m_bytecodeIndex(WTF::HashTableDeletedValue) 51 , m_kind(ExitKindUnset) 52 , m_jitType(ExitFromAnything) 53 , m_inlineKind(ExitFromAnyInlineKind) 54 { 55 } 56 57 explicit FrequentExitSite(BytecodeIndex bytecodeIndex, ExitKind kind, ExitingJITType jitType = ExitFromAnything, ExitingInlineKind inlineKind = ExitFromAnyInlineKind) 58 : m_bytecodeIndex(bytecodeIndex) 59 , m_kind(kind) 60 , m_jitType(jitType) 61 , m_inlineKind(inlineKind) 62 { 63 if (m_kind == ArgumentsEscaped) { 64 // Count this one globally. It doesn't matter where in the code block the arguments excaped; 65 // the fact that they did is not associated with any particular instruction. 66 m_bytecodeIndex = BytecodeIndex(0); 67 } 68 } 69 70 // Use this constructor if you wish for the exit site to be counted globally within its 71 // code block. 72 explicit FrequentExitSite(ExitKind kind, ExitingJITType jitType = ExitFromAnything, ExitingInlineKind inlineKind = ExitFromAnyInlineKind) 73 : m_bytecodeIndex(BytecodeIndex(0)) 74 , m_kind(kind) 75 , m_jitType(jitType) 76 , m_inlineKind(inlineKind) 77 { 78 } 79 80 bool operator!() const 81 { 82 return m_kind == ExitKindUnset; 83 } 84 85 bool operator==(const FrequentExitSite& other) const 86 { 87 return m_bytecodeIndex == other.m_bytecodeIndex 88 && m_kind == other.m_kind 89 && m_jitType == other.m_jitType 90 && m_inlineKind == other.m_inlineKind; 91 } 92 93 bool subsumes(const FrequentExitSite& other) const 94 { 95 if (m_bytecodeIndex != other.m_bytecodeIndex) 96 return false; 97 if (m_kind != other.m_kind) 98 return false; 99 if (m_jitType != ExitFromAnything 100 && m_jitType != other.m_jitType) 101 return false; 102 if (m_inlineKind != ExitFromAnyInlineKind 103 && m_inlineKind != other.m_inlineKind) 104 return false; 105 return true; 106 } 107 108 unsigned hash() const 109 { 110 return m_bytecodeIndex.hash() + m_kind + static_cast<unsigned>(m_jitType) * 7 + static_cast<unsigned>(m_inlineKind) * 11; 111 } 112 113 BytecodeIndex bytecodeIndex() const { return m_bytecodeIndex; } 114 ExitKind kind() const { return m_kind; } 115 ExitingJITType jitType() const { return m_jitType; } 116 ExitingInlineKind inlineKind() const { return m_inlineKind; } 117 118 FrequentExitSite withJITType(ExitingJITType jitType) const 119 { 120 FrequentExitSite result = *this; 121 result.m_jitType = jitType; 122 return result; 123 } 124 125 FrequentExitSite withInlineKind(ExitingInlineKind inlineKind) const 126 { 127 FrequentExitSite result = *this; 128 result.m_inlineKind = inlineKind; 129 return result; 130 } 131 132 bool isHashTableDeletedValue() const 133 { 134 return m_kind == ExitKindUnset && m_bytecodeIndex.isHashTableDeletedValue(); 135 } 136 137 void dump(PrintStream& out) const; 138 139 private: 140 BytecodeIndex m_bytecodeIndex; 141 ExitKind m_kind; 142 ExitingJITType m_jitType; 143 ExitingInlineKind m_inlineKind; 144 }; 145 146 struct FrequentExitSiteHash { 147 static unsigned hash(const FrequentExitSite& key) { return key.hash(); } 148 static bool equal(const FrequentExitSite& a, const FrequentExitSite& b) { return a == b; } 149 static constexpr bool safeToCompareToEmptyOrDeleted = true; 150 }; 151 152 } } // namespace JSC::DFG 153 154 155 namespace WTF { 156 157 template<typename T> struct DefaultHash; 158 template<> struct DefaultHash<JSC::DFG::FrequentExitSite> : JSC::DFG::FrequentExitSiteHash { }; 159 160 template<typename T> struct HashTraits; 161 template<> struct HashTraits<JSC::DFG::FrequentExitSite> : SimpleClassHashTraits<JSC::DFG::FrequentExitSite> { }; 162 163 } // namespace WTF 164 165 namespace JSC { namespace DFG { 166 167 class QueryableExitProfile; 168 169 class ExitProfile { 170 public: 171 ExitProfile(); 172 ~ExitProfile(); 173 174 // Add a new frequent exit site. Return true if this is a new one, or false 175 // if we already knew about it. This is an O(n) operation, because it errs 176 // on the side of keeping the data structure compact. Also, this will only 177 // be called a fixed number of times per recompilation. Recompilation is 178 // rare to begin with, and implies doing O(n) operations on the CodeBlock 179 // anyway. 180 static bool add(CodeBlock*, const FrequentExitSite&); 181 182 // Get the frequent exit sites for a bytecode index. This is O(n), and is 183 // meant to only be used from debugging/profiling code. 184 Vector<FrequentExitSite> exitSitesFor(BytecodeIndex); 185 186 // This is O(n) and should be called on less-frequently executed code paths 187 // in the compiler. It should be strictly cheaper than building a 188 // QueryableExitProfile, if you really expect this to be called infrequently 189 // and you believe that there are few exit sites. 190 bool hasExitSite(const ConcurrentJSLocker&, const FrequentExitSite&) const; 191 bool hasExitSite(const ConcurrentJSLocker& locker, ExitKind kind) const 192 { 193 return hasExitSite(locker, FrequentExitSite(kind)); 194 } 195 196 private: 197 friend class QueryableExitProfile; 198 199 std::unique_ptr<Vector<FrequentExitSite>> m_frequentExitSites; 200 }; 201 202 class QueryableExitProfile { 203 public: 204 QueryableExitProfile(); 205 ~QueryableExitProfile(); 206 207 void initialize(UnlinkedCodeBlock*); 208 209 bool hasExitSite(const FrequentExitSite& site) const 210 { 211 if (site.jitType() == ExitFromAnything) { 212 return hasExitSiteWithSpecificJITType(site.withJITType(ExitFromDFG)) 213 || hasExitSiteWithSpecificJITType(site.withJITType(ExitFromFTL)); 214 } 215 return hasExitSiteWithSpecificJITType(site); 216 } 217 218 bool hasExitSite(ExitKind kind) const 219 { 220 return hasExitSite(FrequentExitSite(kind)); 221 } 222 223 bool hasExitSite(BytecodeIndex bytecodeIndex, ExitKind kind) const 224 { 225 return hasExitSite(FrequentExitSite(bytecodeIndex, kind)); 226 } 227 private: 228 bool hasExitSiteWithSpecificJITType(const FrequentExitSite& site) const 229 { 230 if (site.inlineKind() == ExitFromAnyInlineKind) { 231 return hasExitSiteWithSpecificInlineKind(site.withInlineKind(ExitFromNotInlined)) 232 || hasExitSiteWithSpecificInlineKind(site.withInlineKind(ExitFromInlined)); 233 } 234 return hasExitSiteWithSpecificInlineKind(site); 235 } 236 237 bool hasExitSiteWithSpecificInlineKind(const FrequentExitSite& site) const 238 { 239 return m_frequentExitSites.find(site) != m_frequentExitSites.end(); 240 } 241 242 HashSet<FrequentExitSite> m_frequentExitSites; 243 }; 244 245 } } // namespace JSC::DFG 246 247 #endif // ENABLE(DFG_JIT)