1/*
2 * Copyright (C) 2011-2018 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
37namespace JSC { namespace DFG {
38
39class FrequentExitSite {
40public:
41 FrequentExitSite()
42 : m_bytecodeOffset(0) // 0 = empty value
43 , m_kind(ExitKindUnset)
44 , m_jitType(ExitFromAnything)
45 , m_inlineKind(ExitFromAnyInlineKind)
46 {
47 }
48
49 FrequentExitSite(WTF::HashTableDeletedValueType)
50 : m_bytecodeOffset(1) // 1 = deleted value
51 , m_kind(ExitKindUnset)
52 , m_jitType(ExitFromAnything)
53 , m_inlineKind(ExitFromAnyInlineKind)
54 {
55 }
56
57 explicit FrequentExitSite(unsigned bytecodeOffset, ExitKind kind, ExitingJITType jitType = ExitFromAnything, ExitingInlineKind inlineKind = ExitFromAnyInlineKind)
58 : m_bytecodeOffset(bytecodeOffset)
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_bytecodeOffset = 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_bytecodeOffset(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_bytecodeOffset == other.m_bytecodeOffset
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_bytecodeOffset != other.m_bytecodeOffset)
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 WTF::intHash(m_bytecodeOffset) + m_kind + static_cast<unsigned>(m_jitType) * 7 + static_cast<unsigned>(m_inlineKind) * 11;
111 }
112
113 unsigned bytecodeOffset() const { return m_bytecodeOffset; }
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_bytecodeOffset;
135 }
136
137 void dump(PrintStream& out) const;
138
139private:
140 unsigned m_bytecodeOffset;
141 ExitKind m_kind;
142 ExitingJITType m_jitType;
143 ExitingInlineKind m_inlineKind;
144};
145
146struct 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 const bool safeToCompareToEmptyOrDeleted = true;
150};
151
152} } // namespace JSC::DFG
153
154
155namespace WTF {
156
157template<typename T> struct DefaultHash;
158template<> struct DefaultHash<JSC::DFG::FrequentExitSite> {
159 typedef JSC::DFG::FrequentExitSiteHash Hash;
160};
161
162template<typename T> struct HashTraits;
163template<> struct HashTraits<JSC::DFG::FrequentExitSite> : SimpleClassHashTraits<JSC::DFG::FrequentExitSite> { };
164
165} // namespace WTF
166
167namespace JSC { namespace DFG {
168
169class QueryableExitProfile;
170
171class ExitProfile {
172public:
173 ExitProfile();
174 ~ExitProfile();
175
176 // Add a new frequent exit site. Return true if this is a new one, or false
177 // if we already knew about it. This is an O(n) operation, because it errs
178 // on the side of keeping the data structure compact. Also, this will only
179 // be called a fixed number of times per recompilation. Recompilation is
180 // rare to begin with, and implies doing O(n) operations on the CodeBlock
181 // anyway.
182 static bool add(CodeBlock*, const FrequentExitSite&);
183
184 // Get the frequent exit sites for a bytecode index. This is O(n), and is
185 // meant to only be used from debugging/profiling code.
186 Vector<FrequentExitSite> exitSitesFor(unsigned bytecodeIndex);
187
188 // This is O(n) and should be called on less-frequently executed code paths
189 // in the compiler. It should be strictly cheaper than building a
190 // QueryableExitProfile, if you really expect this to be called infrequently
191 // and you believe that there are few exit sites.
192 bool hasExitSite(const ConcurrentJSLocker&, const FrequentExitSite&) const;
193 bool hasExitSite(const ConcurrentJSLocker& locker, ExitKind kind) const
194 {
195 return hasExitSite(locker, FrequentExitSite(kind));
196 }
197
198private:
199 friend class QueryableExitProfile;
200
201 std::unique_ptr<Vector<FrequentExitSite>> m_frequentExitSites;
202};
203
204class QueryableExitProfile {
205public:
206 QueryableExitProfile();
207 ~QueryableExitProfile();
208
209 void initialize(UnlinkedCodeBlock*);
210
211 bool hasExitSite(const FrequentExitSite& site) const
212 {
213 if (site.jitType() == ExitFromAnything) {
214 return hasExitSiteWithSpecificJITType(site.withJITType(ExitFromDFG))
215 || hasExitSiteWithSpecificJITType(site.withJITType(ExitFromFTL));
216 }
217 return hasExitSiteWithSpecificJITType(site);
218 }
219
220 bool hasExitSite(ExitKind kind) const
221 {
222 return hasExitSite(FrequentExitSite(kind));
223 }
224
225 bool hasExitSite(unsigned bytecodeIndex, ExitKind kind) const
226 {
227 return hasExitSite(FrequentExitSite(bytecodeIndex, kind));
228 }
229private:
230 bool hasExitSiteWithSpecificJITType(const FrequentExitSite& site) const
231 {
232 if (site.inlineKind() == ExitFromAnyInlineKind) {
233 return hasExitSiteWithSpecificInlineKind(site.withInlineKind(ExitFromNotInlined))
234 || hasExitSiteWithSpecificInlineKind(site.withInlineKind(ExitFromInlined));
235 }
236 return hasExitSiteWithSpecificInlineKind(site);
237 }
238
239 bool hasExitSiteWithSpecificInlineKind(const FrequentExitSite& site) const
240 {
241 return m_frequentExitSites.find(site) != m_frequentExitSites.end();
242 }
243
244 HashSet<FrequentExitSite> m_frequentExitSites;
245};
246
247} } // namespace JSC::DFG
248
249#endif // ENABLE(DFG_JIT)
250