1/* 2 * Copyright (C) 2011, 2012, 2013, 2014 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#ifndef DFGExitProfile_h 27#define DFGExitProfile_h 28 29#if ENABLE(DFG_JIT) 30 31#include "ConcurrentJITLock.h" 32#include "ExitKind.h" 33#include "ExitingJITType.h" 34#include <wtf/HashSet.h> 35#include <wtf/OwnPtr.h> 36#include <wtf/Vector.h> 37 38namespace JSC { namespace DFG { 39 40class FrequentExitSite { 41public: 42 FrequentExitSite() 43 : m_bytecodeOffset(0) // 0 = empty value 44 , m_kind(ExitKindUnset) 45 , m_jitType(ExitFromAnything) 46 { 47 } 48 49 FrequentExitSite(WTF::HashTableDeletedValueType) 50 : m_bytecodeOffset(1) // 1 = deleted value 51 , m_kind(ExitKindUnset) 52 , m_jitType(ExitFromAnything) 53 { 54 } 55 56 explicit FrequentExitSite(unsigned bytecodeOffset, ExitKind kind, ExitingJITType jitType = ExitFromAnything) 57 : m_bytecodeOffset(bytecodeOffset) 58 , m_kind(kind) 59 , m_jitType(jitType) 60 { 61 if (m_kind == ArgumentsEscaped) { 62 // Count this one globally. It doesn't matter where in the code block the arguments excaped; 63 // the fact that they did is not associated with any particular instruction. 64 m_bytecodeOffset = 0; 65 } 66 } 67 68 // Use this constructor if you wish for the exit site to be counted globally within its 69 // code block. 70 explicit FrequentExitSite(ExitKind kind, ExitingJITType jitType = ExitFromAnything) 71 : m_bytecodeOffset(0) 72 , m_kind(kind) 73 , m_jitType(jitType) 74 { 75 } 76 77 bool operator!() const 78 { 79 return m_kind == ExitKindUnset; 80 } 81 82 bool operator==(const FrequentExitSite& other) const 83 { 84 return m_bytecodeOffset == other.m_bytecodeOffset 85 && m_kind == other.m_kind 86 && m_jitType == other.m_jitType; 87 } 88 89 bool subsumes(const FrequentExitSite& other) const 90 { 91 if (m_bytecodeOffset != other.m_bytecodeOffset) 92 return false; 93 if (m_kind != other.m_kind) 94 return false; 95 if (m_jitType == ExitFromAnything) 96 return true; 97 return m_jitType == other.m_jitType; 98 } 99 100 unsigned hash() const 101 { 102 return WTF::intHash(m_bytecodeOffset) + m_kind + m_jitType * 7; 103 } 104 105 unsigned bytecodeOffset() const { return m_bytecodeOffset; } 106 ExitKind kind() const { return m_kind; } 107 ExitingJITType jitType() const { return m_jitType; } 108 109 FrequentExitSite withJITType(ExitingJITType jitType) const 110 { 111 FrequentExitSite result = *this; 112 result.m_jitType = jitType; 113 return result; 114 } 115 116 bool isHashTableDeletedValue() const 117 { 118 return m_kind == ExitKindUnset && m_bytecodeOffset; 119 } 120 121private: 122 unsigned m_bytecodeOffset; 123 ExitKind m_kind; 124 ExitingJITType m_jitType; 125}; 126 127struct FrequentExitSiteHash { 128 static unsigned hash(const FrequentExitSite& key) { return key.hash(); } 129 static bool equal(const FrequentExitSite& a, const FrequentExitSite& b) { return a == b; } 130 static const bool safeToCompareToEmptyOrDeleted = true; 131}; 132 133} } // namespace JSC::DFG 134 135 136namespace WTF { 137 138template<typename T> struct DefaultHash; 139template<> struct DefaultHash<JSC::DFG::FrequentExitSite> { 140 typedef JSC::DFG::FrequentExitSiteHash Hash; 141}; 142 143template<typename T> struct HashTraits; 144template<> struct HashTraits<JSC::DFG::FrequentExitSite> : SimpleClassHashTraits<JSC::DFG::FrequentExitSite> { }; 145 146} // namespace WTF 147 148namespace JSC { namespace DFG { 149 150class QueryableExitProfile; 151 152class ExitProfile { 153public: 154 ExitProfile(); 155 ~ExitProfile(); 156 157 // Add a new frequent exit site. Return true if this is a new one, or false 158 // if we already knew about it. This is an O(n) operation, because it errs 159 // on the side of keeping the data structure compact. Also, this will only 160 // be called a fixed number of times per recompilation. Recompilation is 161 // rare to begin with, and implies doing O(n) operations on the CodeBlock 162 // anyway. 163 bool add(const ConcurrentJITLocker&, const FrequentExitSite&); 164 165 // Get the frequent exit sites for a bytecode index. This is O(n), and is 166 // meant to only be used from debugging/profiling code. 167 Vector<FrequentExitSite> exitSitesFor(unsigned bytecodeIndex); 168 169 // This is O(n) and should be called on less-frequently executed code paths 170 // in the compiler. It should be strictly cheaper than building a 171 // QueryableExitProfile, if you really expect this to be called infrequently 172 // and you believe that there are few exit sites. 173 bool hasExitSite(const ConcurrentJITLocker&, const FrequentExitSite&) const; 174 bool hasExitSite(const ConcurrentJITLocker& locker, ExitKind kind) const 175 { 176 return hasExitSite(locker, FrequentExitSite(kind)); 177 } 178 bool hasExitSite(const ConcurrentJITLocker& locker, unsigned bytecodeIndex, ExitKind kind) const 179 { 180 return hasExitSite(locker, FrequentExitSite(bytecodeIndex, kind)); 181 } 182 183private: 184 friend class QueryableExitProfile; 185 186 OwnPtr<Vector<FrequentExitSite>> m_frequentExitSites; 187}; 188 189class QueryableExitProfile { 190public: 191 QueryableExitProfile(); 192 ~QueryableExitProfile(); 193 194 void initialize(const ConcurrentJITLocker&, const ExitProfile&); 195 196 bool hasExitSite(const FrequentExitSite& site) const 197 { 198 if (site.jitType() == ExitFromAnything) { 199 return hasExitSite(site.withJITType(ExitFromDFG)) 200 || hasExitSite(site.withJITType(ExitFromFTL)); 201 } 202 return m_frequentExitSites.find(site) != m_frequentExitSites.end(); 203 } 204 205 bool hasExitSite(ExitKind kind) const 206 { 207 return hasExitSite(FrequentExitSite(kind)); 208 } 209 210 bool hasExitSite(unsigned bytecodeIndex, ExitKind kind) const 211 { 212 return hasExitSite(FrequentExitSite(bytecodeIndex, kind)); 213 } 214private: 215 HashSet<FrequentExitSite> m_frequentExitSites; 216}; 217 218} } // namespace JSC::DFG 219 220#endif // ENABLE(DFG_JIT) 221 222#endif // DFGExitProfile_h 223