fourthTier: should use ConcurrentJITLock[er] directly and not through typedef
[WebKit-https.git] / Source / JavaScriptCore / bytecode / ValueProfile.h
1 /*
2  * Copyright (C) 2011, 2012, 2013 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #ifndef ValueProfile_h
30 #define ValueProfile_h
31
32 #include <wtf/Platform.h>
33
34 #if ENABLE(VALUE_PROFILER)
35
36 #include "ConcurrentJITLock.h"
37 #include "Heap.h"
38 #include "JSArray.h"
39 #include "SpeculatedType.h"
40 #include "Structure.h"
41 #include "WriteBarrier.h"
42 #include <wtf/PrintStream.h>
43 #include <wtf/StringPrintStream.h>
44
45 namespace JSC {
46
47 template<unsigned numberOfBucketsArgument>
48 struct ValueProfileBase {
49     static const unsigned numberOfBuckets = numberOfBucketsArgument;
50     static const unsigned numberOfSpecFailBuckets = 1;
51     static const unsigned bucketIndexMask = numberOfBuckets - 1;
52     static const unsigned totalNumberOfBuckets = numberOfBuckets + numberOfSpecFailBuckets;
53     
54     ValueProfileBase()
55         : m_bytecodeOffset(-1)
56         , m_prediction(SpecNone)
57         , m_numberOfSamplesInPrediction(0)
58         , m_singletonValueIsTop(false)
59     {
60         for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
61             m_buckets[i] = JSValue::encode(JSValue());
62     }
63     
64     ValueProfileBase(int bytecodeOffset)
65         : m_bytecodeOffset(bytecodeOffset)
66         , m_prediction(SpecNone)
67         , m_numberOfSamplesInPrediction(0)
68         , m_singletonValueIsTop(false)
69     {
70         for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
71             m_buckets[i] = JSValue::encode(JSValue());
72     }
73     
74     EncodedJSValue* specFailBucket(unsigned i)
75     {
76         ASSERT(numberOfBuckets + i < totalNumberOfBuckets);
77         return m_buckets + numberOfBuckets + i;
78     }
79     
80     const ClassInfo* classInfo(unsigned bucket) const
81     {
82         JSValue value = JSValue::decode(m_buckets[bucket]);
83         if (!!value) {
84             if (!value.isCell())
85                 return 0;
86             return value.asCell()->structure()->classInfo();
87         }
88         return 0;
89     }
90     
91     unsigned numberOfSamples() const
92     {
93         unsigned result = 0;
94         for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
95             if (!!JSValue::decode(m_buckets[i]))
96                 result++;
97         }
98         return result;
99     }
100     
101     unsigned totalNumberOfSamples() const
102     {
103         return numberOfSamples() + m_numberOfSamplesInPrediction;
104     }
105     
106     bool isLive() const
107     {
108         for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
109             if (!!JSValue::decode(m_buckets[i]))
110                 return true;
111         }
112         return false;
113     }
114     
115     CString briefDescription(const ConcurrentJITLocker& locker)
116     {
117         computeUpdatedPrediction(locker);
118         
119         StringPrintStream out;
120         
121         if (m_singletonValueIsTop)
122             out.print("predicting ", SpeculationDump(m_prediction));
123         else if (m_singletonValue)
124             out.print("predicting ", m_singletonValue);
125         
126         return out.toCString();
127     }
128     
129     void dump(PrintStream& out)
130     {
131         out.print("samples = ", totalNumberOfSamples(), " prediction = ", SpeculationDump(m_prediction));
132         out.printf(", value = ");
133         if (m_singletonValueIsTop)
134             out.printf("TOP");
135         else
136             out.print(m_singletonValue);
137         bool first = true;
138         for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
139             JSValue value = JSValue::decode(m_buckets[i]);
140             if (!!value) {
141                 if (first) {
142                     out.printf(": ");
143                     first = false;
144                 } else
145                     out.printf(", ");
146                 out.print(value);
147             }
148         }
149     }
150     
151     // Updates the prediction and returns the new one. Never call this from any thread
152     // that isn't executing the code.
153     SpeculatedType computeUpdatedPrediction(const ConcurrentJITLocker&, OperationInProgress operation = NoOperation)
154     {
155         for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
156             JSValue value = JSValue::decode(m_buckets[i]);
157             if (!value)
158                 continue;
159             
160             m_numberOfSamplesInPrediction++;
161             mergeSpeculation(m_prediction, speculationFromValue(value));
162             
163             if (!m_singletonValueIsTop && !!value) {
164                 if (!m_singletonValue)
165                     m_singletonValue = value;
166                 else if (m_singletonValue != value)
167                     m_singletonValueIsTop = true;
168             }
169             
170             m_buckets[i] = JSValue::encode(JSValue());
171         }
172         
173         if (operation == Collection
174             && !m_singletonValueIsTop
175             && !!m_singletonValue
176             && m_singletonValue.isCell()
177             && !Heap::isMarked(m_singletonValue.asCell()))
178             m_singletonValueIsTop = true;
179             
180         return m_prediction;
181     }
182     
183     int m_bytecodeOffset; // -1 for prologue
184     
185     SpeculatedType m_prediction;
186     unsigned m_numberOfSamplesInPrediction;
187     
188     bool m_singletonValueIsTop;
189     JSValue m_singletonValue;
190
191     EncodedJSValue m_buckets[totalNumberOfBuckets];
192 };
193
194 struct MinimalValueProfile : public ValueProfileBase<0> {
195     MinimalValueProfile(): ValueProfileBase<0>() { }
196     MinimalValueProfile(int bytecodeOffset): ValueProfileBase<0>(bytecodeOffset) { }
197 };
198
199 template<unsigned logNumberOfBucketsArgument>
200 struct ValueProfileWithLogNumberOfBuckets : public ValueProfileBase<1 << logNumberOfBucketsArgument> {
201     static const unsigned logNumberOfBuckets = logNumberOfBucketsArgument;
202     
203     ValueProfileWithLogNumberOfBuckets()
204         : ValueProfileBase<1 << logNumberOfBucketsArgument>()
205     {
206     }
207     ValueProfileWithLogNumberOfBuckets(int bytecodeOffset)
208         : ValueProfileBase<1 << logNumberOfBucketsArgument>(bytecodeOffset)
209     {
210     }
211 };
212
213 struct ValueProfile : public ValueProfileWithLogNumberOfBuckets<0> {
214     ValueProfile(): ValueProfileWithLogNumberOfBuckets<0>() { }
215     ValueProfile(int bytecodeOffset): ValueProfileWithLogNumberOfBuckets<0>(bytecodeOffset) { }
216 };
217
218 template<typename T>
219 inline int getValueProfileBytecodeOffset(T* valueProfile)
220 {
221     return valueProfile->m_bytecodeOffset;
222 }
223
224 // This is a mini value profile to catch pathologies. It is a counter that gets
225 // incremented when we take the slow path on any instruction.
226 struct RareCaseProfile {
227     RareCaseProfile(int bytecodeOffset)
228         : m_bytecodeOffset(bytecodeOffset)
229         , m_counter(0)
230     {
231     }
232     
233     int m_bytecodeOffset;
234     uint32_t m_counter;
235 };
236
237 inline int getRareCaseProfileBytecodeOffset(RareCaseProfile* rareCaseProfile)
238 {
239     return rareCaseProfile->m_bytecodeOffset;
240 }
241
242 } // namespace JSC
243
244 #endif // ENABLE(VALUE_PROFILER)
245
246 #endif // ValueProfile_h
247