We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / bytecode / DFGExitProfile.h
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
37 namespace JSC { namespace DFG {
38
39 class FrequentExitSite {
40 public:
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
139 private:
140     unsigned m_bytecodeOffset;
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 const 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> {
159     typedef JSC::DFG::FrequentExitSiteHash Hash;
160 };
161
162 template<typename T> struct HashTraits;
163 template<> struct HashTraits<JSC::DFG::FrequentExitSite> : SimpleClassHashTraits<JSC::DFG::FrequentExitSite> { };
164
165 } // namespace WTF
166
167 namespace JSC { namespace DFG {
168
169 class QueryableExitProfile;
170
171 class ExitProfile {
172 public:
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     
198 private:
199     friend class QueryableExitProfile;
200     
201     std::unique_ptr<Vector<FrequentExitSite>> m_frequentExitSites;
202 };
203
204 class QueryableExitProfile {
205 public:
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     }
229 private:
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)