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