DFG should be able to set watchpoints on global variables
[WebKit-https.git] / Source / JavaScriptCore / bytecode / DFGExitProfile.h
1 /*
2  * Copyright (C) 2011 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 #include <wtf/HashSet.h>
30 #include <wtf/OwnPtr.h>
31 #include <wtf/Vector.h>
32
33 namespace JSC { namespace DFG {
34
35 enum ExitKind {
36     ExitKindUnset,
37     BadType, // We exited because a type prediction was wrong.
38     BadCache, // We exited because an inline cache was wrong.
39     Overflow, // We exited because of overflow.
40     NegativeZero, // We exited because we encountered negative zero.
41     InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage.
42     ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to.
43     Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
44     UncountableWatchpoint // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves.
45 };
46
47 inline const char* exitKindToString(ExitKind kind)
48 {
49     switch (kind) {
50     case ExitKindUnset:
51         return "Unset";
52     case BadType:
53         return "BadType";
54     case BadCache:
55         return "BadCache";
56     case Overflow:
57         return "Overflow";
58     case NegativeZero:
59         return "NegativeZero";
60     case InadequateCoverage:
61         return "InadequateCoverage";
62     case ArgumentsEscaped:
63         return "ArgumentsEscaped";
64     case Uncountable:
65         return "Uncountable";
66     case UncountableWatchpoint:
67         return "UncountableWatchpoint";
68     default:
69         return "Unknown";
70     }
71 }
72
73 inline bool exitKindIsCountable(ExitKind kind)
74 {
75     switch (kind) {
76     case ExitKindUnset:
77         ASSERT_NOT_REACHED();
78     case BadType:
79     case Uncountable:
80     case UncountableWatchpoint:
81         return false;
82     default:
83         return true;
84     }
85 }
86
87 class FrequentExitSite {
88 public:
89     FrequentExitSite()
90         : m_bytecodeOffset(0) // 0 = empty value
91         , m_kind(ExitKindUnset)
92     {
93     }
94     
95     FrequentExitSite(WTF::HashTableDeletedValueType)
96         : m_bytecodeOffset(1) // 1 = deleted value
97         , m_kind(ExitKindUnset)
98     {
99     }
100     
101     explicit FrequentExitSite(unsigned bytecodeOffset, ExitKind kind)
102         : m_bytecodeOffset(bytecodeOffset)
103         , m_kind(kind)
104     {
105         ASSERT(exitKindIsCountable(kind));
106     }
107     
108     // Use this constructor if you wish for the exit site to be counted globally within its
109     // code block.
110     explicit FrequentExitSite(ExitKind kind)
111         : m_bytecodeOffset(0)
112         , m_kind(kind)
113     {
114         ASSERT(exitKindIsCountable(kind));
115     }
116     
117     bool operator!() const
118     {
119         return m_kind == ExitKindUnset;
120     }
121     
122     bool operator==(const FrequentExitSite& other) const
123     {
124         return m_bytecodeOffset == other.m_bytecodeOffset
125             && m_kind == other.m_kind;
126     }
127     
128     unsigned hash() const
129     {
130         return WTF::intHash(m_bytecodeOffset) + m_kind;
131     }
132     
133     unsigned bytecodeOffset() const { return m_bytecodeOffset; }
134     ExitKind kind() const { return m_kind; }
135
136     bool isHashTableDeletedValue() const
137     {
138         return m_kind == ExitKindUnset && m_bytecodeOffset;
139     }
140
141 private:
142     unsigned m_bytecodeOffset;
143     ExitKind m_kind;
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 namespace WTF {
155
156 template<typename T> struct DefaultHash;
157 template<> struct DefaultHash<JSC::DFG::FrequentExitSite> {
158     typedef JSC::DFG::FrequentExitSiteHash Hash;
159 };
160
161 template<typename T> struct HashTraits;
162 template<> struct HashTraits<JSC::DFG::FrequentExitSite> : SimpleClassHashTraits<JSC::DFG::FrequentExitSite> { };
163
164 } // namespace WTF
165
166 namespace JSC { namespace DFG {
167
168 class QueryableExitProfile;
169
170 class ExitProfile {
171 public:
172     ExitProfile();
173     ~ExitProfile();
174     
175     // Add a new frequent exit site. Return true if this is a new one, or false
176     // if we already knew about it. This is an O(n) operation, because it errs
177     // on the side of keeping the data structure compact. Also, this will only
178     // be called a fixed number of times per recompilation. Recompilation is
179     // rare to begin with, and implies doing O(n) operations on the CodeBlock
180     // anyway.
181     bool add(const FrequentExitSite&);
182     
183 private:
184     friend class QueryableExitProfile;
185     
186     OwnPtr<Vector<FrequentExitSite> > m_frequentExitSites;
187 };
188
189 class QueryableExitProfile {
190 public:
191     explicit QueryableExitProfile(const ExitProfile&);
192     ~QueryableExitProfile();
193     
194     bool hasExitSite(const FrequentExitSite& site) const
195     {
196         return m_frequentExitSites.find(site) != m_frequentExitSites.end();
197     }
198     
199     bool hasExitSite(ExitKind kind) const
200     {
201         return hasExitSite(FrequentExitSite(kind));
202     }
203     
204     bool hasExitSite(unsigned bytecodeIndex, ExitKind kind) const
205     {
206         return hasExitSite(FrequentExitSite(bytecodeIndex, kind));
207     }
208 private:
209     HashSet<FrequentExitSite> m_frequentExitSites;
210 };
211
212 } } // namespace JSC::DFG
213
214 #endif // DFGExitProfile_h