]>
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 A |
34 | #include <wtf/HashSet.h> |
35 | #include <wtf/OwnPtr.h> | |
36 | #include <wtf/Vector.h> | |
37 | ||
38 | namespace JSC { namespace DFG { | |
39 | ||
6fe7ccc8 A |
40 | class FrequentExitSite { |
41 | public: | |
42 | FrequentExitSite() | |
43 | : m_bytecodeOffset(0) // 0 = empty value | |
44 | , m_kind(ExitKindUnset) | |
81345200 | 45 | , m_jitType(ExitFromAnything) |
6fe7ccc8 A |
46 | { |
47 | } | |
48 | ||
49 | FrequentExitSite(WTF::HashTableDeletedValueType) | |
50 | : m_bytecodeOffset(1) // 1 = deleted value | |
51 | , m_kind(ExitKindUnset) | |
81345200 | 52 | , m_jitType(ExitFromAnything) |
6fe7ccc8 A |
53 | { |
54 | } | |
55 | ||
81345200 | 56 | explicit FrequentExitSite(unsigned bytecodeOffset, ExitKind kind, ExitingJITType jitType = ExitFromAnything) |
6fe7ccc8 A |
57 | : m_bytecodeOffset(bytecodeOffset) |
58 | , m_kind(kind) | |
81345200 | 59 | , m_jitType(jitType) |
6fe7ccc8 | 60 | { |
81345200 A |
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 | } | |
6fe7ccc8 A |
66 | } |
67 | ||
93a37866 A |
68 | // Use this constructor if you wish for the exit site to be counted globally within its |
69 | // code block. | |
81345200 | 70 | explicit FrequentExitSite(ExitKind kind, ExitingJITType jitType = ExitFromAnything) |
93a37866 A |
71 | : m_bytecodeOffset(0) |
72 | , m_kind(kind) | |
81345200 | 73 | , m_jitType(jitType) |
93a37866 | 74 | { |
93a37866 A |
75 | } |
76 | ||
6fe7ccc8 A |
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 | |
81345200 A |
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; | |
6fe7ccc8 A |
98 | } |
99 | ||
100 | unsigned hash() const | |
101 | { | |
81345200 | 102 | return WTF::intHash(m_bytecodeOffset) + m_kind + m_jitType * 7; |
6fe7ccc8 A |
103 | } |
104 | ||
105 | unsigned bytecodeOffset() const { return m_bytecodeOffset; } | |
106 | ExitKind kind() const { return m_kind; } | |
81345200 A |
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 | } | |
6fe7ccc8 A |
115 | |
116 | bool isHashTableDeletedValue() const | |
117 | { | |
118 | return m_kind == ExitKindUnset && m_bytecodeOffset; | |
119 | } | |
120 | ||
121 | private: | |
122 | unsigned m_bytecodeOffset; | |
123 | ExitKind m_kind; | |
81345200 | 124 | ExitingJITType m_jitType; |
6fe7ccc8 A |
125 | }; |
126 | ||
127 | struct 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 | ||
81345200 | 135 | |
6fe7ccc8 A |
136 | namespace WTF { |
137 | ||
138 | template<typename T> struct DefaultHash; | |
139 | template<> struct DefaultHash<JSC::DFG::FrequentExitSite> { | |
140 | typedef JSC::DFG::FrequentExitSiteHash Hash; | |
141 | }; | |
142 | ||
143 | template<typename T> struct HashTraits; | |
144 | template<> struct HashTraits<JSC::DFG::FrequentExitSite> : SimpleClassHashTraits<JSC::DFG::FrequentExitSite> { }; | |
145 | ||
146 | } // namespace WTF | |
147 | ||
148 | namespace JSC { namespace DFG { | |
149 | ||
150 | class QueryableExitProfile; | |
151 | ||
152 | class ExitProfile { | |
153 | public: | |
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. | |
81345200 | 163 | bool add(const ConcurrentJITLocker&, const FrequentExitSite&); |
6fe7ccc8 | 164 | |
93a37866 A |
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. | |
81345200 A |
173 | bool hasExitSite(const ConcurrentJITLocker&, const FrequentExitSite&) const; |
174 | bool hasExitSite(const ConcurrentJITLocker& locker, ExitKind kind) const | |
93a37866 | 175 | { |
81345200 | 176 | return hasExitSite(locker, FrequentExitSite(kind)); |
93a37866 | 177 | } |
81345200 | 178 | bool hasExitSite(const ConcurrentJITLocker& locker, unsigned bytecodeIndex, ExitKind kind) const |
93a37866 | 179 | { |
81345200 | 180 | return hasExitSite(locker, FrequentExitSite(bytecodeIndex, kind)); |
93a37866 A |
181 | } |
182 | ||
6fe7ccc8 A |
183 | private: |
184 | friend class QueryableExitProfile; | |
185 | ||
81345200 | 186 | OwnPtr<Vector<FrequentExitSite>> m_frequentExitSites; |
6fe7ccc8 A |
187 | }; |
188 | ||
189 | class QueryableExitProfile { | |
190 | public: | |
81345200 | 191 | QueryableExitProfile(); |
6fe7ccc8 A |
192 | ~QueryableExitProfile(); |
193 | ||
81345200 A |
194 | void initialize(const ConcurrentJITLocker&, const ExitProfile&); |
195 | ||
6fe7ccc8 A |
196 | bool hasExitSite(const FrequentExitSite& site) const |
197 | { | |
81345200 A |
198 | if (site.jitType() == ExitFromAnything) { |
199 | return hasExitSite(site.withJITType(ExitFromDFG)) | |
200 | || hasExitSite(site.withJITType(ExitFromFTL)); | |
201 | } | |
6fe7ccc8 A |
202 | return m_frequentExitSites.find(site) != m_frequentExitSites.end(); |
203 | } | |
204 | ||
93a37866 A |
205 | bool hasExitSite(ExitKind kind) const |
206 | { | |
207 | return hasExitSite(FrequentExitSite(kind)); | |
208 | } | |
209 | ||
6fe7ccc8 A |
210 | bool hasExitSite(unsigned bytecodeIndex, ExitKind kind) const |
211 | { | |
212 | return hasExitSite(FrequentExitSite(bytecodeIndex, kind)); | |
213 | } | |
214 | private: | |
215 | HashSet<FrequentExitSite> m_frequentExitSites; | |
216 | }; | |
217 | ||
218 | } } // namespace JSC::DFG | |
219 | ||
81345200 A |
220 | #endif // ENABLE(DFG_JIT) |
221 | ||
6fe7ccc8 | 222 | #endif // DFGExitProfile_h |