initial import
[vuplus_webkit] / Source / JavaScriptCore / bytecode / ValueProfile.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  *
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 "JSArray.h"
33 #include "PredictedType.h"
34 #include "Structure.h"
35 #include "WriteBarrier.h"
36
37 namespace JSC {
38
39 #if ENABLE(VALUE_PROFILER)
40 struct ValueProfile {
41     static const unsigned logNumberOfBuckets = 3; // 8 buckets
42     static const unsigned numberOfBuckets = 1 << logNumberOfBuckets;
43     static const unsigned bucketIndexMask = numberOfBuckets - 1;
44     static const unsigned certainty = numberOfBuckets * numberOfBuckets;
45     static const unsigned majority = certainty / 2;
46     
47     ValueProfile(int bytecodeOffset)
48         : m_bytecodeOffset(bytecodeOffset)
49         , m_prediction(PredictNone)
50         , m_numberOfSamplesInPrediction(0)
51     {
52         for (unsigned i = 0; i < numberOfBuckets; ++i)
53             m_buckets[i] = JSValue::encode(JSValue());
54     }
55     
56     const ClassInfo* classInfo(unsigned bucket) const
57     {
58         if (!!m_buckets[bucket]) {
59             JSValue value = JSValue::decode(m_buckets[bucket]);
60             if (!value.isCell())
61                 return 0;
62             return value.asCell()->structure()->classInfo();
63         }
64         return m_weakBuckets[bucket].getClassInfo();
65     }
66     
67     unsigned numberOfSamples() const
68     {
69         unsigned result = 0;
70         for (unsigned i = 0; i < numberOfBuckets; ++i) {
71             if (!!m_buckets[i] || !!m_weakBuckets[i])
72                 result++;
73         }
74         return result;
75     }
76     
77     unsigned totalNumberOfSamples() const
78     {
79         return numberOfSamples() + m_numberOfSamplesInPrediction;
80     }
81     
82     bool isLive() const
83     {
84         for (unsigned i = 0; i < numberOfBuckets; ++i) {
85             if (!!m_buckets[i] || !!m_weakBuckets[i])
86                 return true;
87         }
88         return false;
89     }
90     
91     static unsigned computeProbability(unsigned counts, unsigned numberOfSamples)
92     {
93         if (!numberOfSamples)
94             return 0;
95         return counts * certainty / numberOfSamples;
96     }
97     
98     unsigned numberOfInt32s() const
99     {
100         unsigned result = 0;
101         for (unsigned i = 0; i < numberOfBuckets; ++i) {
102             if (!!m_buckets[i] && JSValue::decode(m_buckets[i]).isInt32())
103                 result++;
104         }
105         return result;
106     }
107         
108     unsigned numberOfDoubles() const
109     {
110         unsigned result = 0;
111         for (unsigned i = 0; i < numberOfBuckets; ++i) {
112             if (!!m_buckets[i] && JSValue::decode(m_buckets[i]).isDouble())
113                 result++;
114         }
115         return result;
116     }
117         
118     unsigned numberOfCells() const
119     {
120         unsigned result = 0;
121         for (unsigned i = 0; i < numberOfBuckets; ++i) {
122             if (!!classInfo(i))
123                 result++;
124         }
125         return result;
126     }
127     
128     unsigned numberOfObjects() const
129     {
130         unsigned result = 0;
131         for (unsigned i = 0; i < numberOfBuckets; ++i) {
132             const ClassInfo* ci = classInfo(i);
133             if (!!ci && ci->isSubClassOf(&JSObject::s_info))
134                 result++;
135         }
136         return result;
137     }
138     
139     unsigned numberOfFinalObjects() const
140     {
141         unsigned result = 0;
142         for (unsigned i = 0; i < numberOfBuckets; ++i) {
143             if (classInfo(i) == &JSFinalObject::s_info)
144                 result++;
145         }
146         return result;
147     }
148     
149     unsigned numberOfStrings() const
150     {
151         unsigned result = 0;
152         for (unsigned i = 0; i < numberOfBuckets; ++i) {
153             if (classInfo(i) == &JSString::s_info)
154                 result++;
155         }
156         return result;
157     }
158     
159     unsigned numberOfArrays() const
160     {
161         unsigned result = 0;
162         for (unsigned i = 0; i < numberOfBuckets; ++i) {
163             if (classInfo(i) == &JSArray::s_info)
164                 result++;
165         }
166         return result;
167     }
168     
169     unsigned numberOfBooleans() const
170     {
171         unsigned result = 0;
172         for (unsigned i = 0; i < numberOfBuckets; ++i) {
173             if (!!m_buckets[i] && JSValue::decode(m_buckets[i]).isBoolean())
174                 result++;
175         }
176         return result;
177     }
178         
179     // These methods are not particularly optimized, in that they will each
180     // perform two passes over the buckets array. However, they are
181     // probably the best bet unless you are sure that you will be making
182     // these calls with high frequency.
183         
184     unsigned probabilityOfInt32() const
185     {
186         return computeProbability(numberOfInt32s(), numberOfSamples());
187     }
188         
189     unsigned probabilityOfDouble() const
190     {
191         return computeProbability(numberOfDoubles(), numberOfSamples());
192     }
193     
194     unsigned probabilityOfCell() const
195     {
196         return computeProbability(numberOfCells(), numberOfSamples());
197     }
198     
199     unsigned probabilityOfObject() const
200     {
201         return computeProbability(numberOfObjects(), numberOfSamples());
202     }
203     
204     unsigned probabilityOfFinalObject() const
205     {
206         return computeProbability(numberOfFinalObjects(), numberOfSamples());
207     }
208     
209     unsigned probabilityOfArray() const
210     {
211         return computeProbability(numberOfArrays(), numberOfSamples());
212     }
213     
214     unsigned probabilityOfString() const
215     {
216         return computeProbability(numberOfStrings(), numberOfSamples());
217     }
218     
219     unsigned probabilityOfBoolean() const
220     {
221         return computeProbability(numberOfBooleans(), numberOfSamples());
222     }
223
224 #ifndef NDEBUG
225     void dump(FILE* out)
226     {
227         fprintf(out,
228                 "samples = %u, int32 = %u (%u), double = %u (%u), cell = %u (%u), object = %u (%u), final object = %u (%u), array = %u (%u), string = %u (%u), boolean = %u (%u), prediction = %s, samples in prediction = %u",
229                 numberOfSamples(),
230                 probabilityOfInt32(), numberOfInt32s(),
231                 probabilityOfDouble(), numberOfDoubles(),
232                 probabilityOfCell(), numberOfCells(),
233                 probabilityOfObject(), numberOfObjects(),
234                 probabilityOfFinalObject(), numberOfFinalObjects(),
235                 probabilityOfArray(), numberOfArrays(),
236                 probabilityOfString(), numberOfStrings(),
237                 probabilityOfBoolean(), numberOfBooleans(),
238                 predictionToString(m_prediction), m_numberOfSamplesInPrediction);
239         bool first = true;
240         for (unsigned i = 0; i < numberOfBuckets; ++i) {
241             if (!!m_buckets[i] || !!m_weakBuckets[i]) {
242                 if (first) {
243                     fprintf(out, ": ");
244                     first = false;
245                 } else
246                     fprintf(out, ", ");
247             }
248             
249             if (!!m_buckets[i])
250                 fprintf(out, "%s", JSValue::decode(m_buckets[i]).description());
251             
252             if (!!m_weakBuckets[i])
253                 fprintf(out, "DeadCell");
254         }
255     }
256 #endif
257     
258     struct Statistics {
259         unsigned samples;
260         unsigned int32s;
261         unsigned doubles;
262         unsigned cells;
263         unsigned objects;
264         unsigned finalObjects;
265         unsigned arrays;
266         unsigned strings;
267         unsigned booleans;
268         
269         Statistics()
270         {
271             bzero(this, sizeof(Statistics));
272         }
273     };
274     
275     // Method for incrementing all relevant statistics for a ClassInfo, except for
276     // incrementing the number of samples, which the caller is responsible for
277     // doing.
278     static void computeStatistics(const ClassInfo*, Statistics&);
279
280     // Optimized method for getting all counts at once.
281     void computeStatistics(Statistics&) const;
282     
283     // Updates the prediction and returns the new one.
284     PredictedType computeUpdatedPrediction();
285     
286     int m_bytecodeOffset; // -1 for prologue
287     
288     PredictedType m_prediction;
289     unsigned m_numberOfSamplesInPrediction;
290     
291     EncodedJSValue m_buckets[numberOfBuckets];
292     
293     class WeakBucket {
294     public:
295         WeakBucket()
296             : m_value(0)
297         {
298         }
299         
300         WeakBucket(Structure* structure)
301             : m_value(reinterpret_cast<uintptr_t>(structure))
302         {
303         }
304         
305         WeakBucket(const ClassInfo* classInfo)
306             : m_value(reinterpret_cast<uintptr_t>(classInfo) | 1)
307         {
308         }
309         
310         bool operator!() const
311         {
312             return !m_value;
313         }
314         
315         bool isEmpty() const
316         {
317             return !m_value;
318         }
319         
320         bool isClassInfo() const
321         {
322             return !!(m_value & 1);
323         }
324         
325         bool isStructure() const
326         {
327             return !isEmpty() && !isClassInfo();
328         }
329         
330         Structure* asStructure() const
331         {
332             ASSERT(isStructure());
333             return reinterpret_cast<Structure*>(m_value);
334         }
335         
336         const ClassInfo* asClassInfo() const
337         {
338             ASSERT(isClassInfo());
339             return reinterpret_cast<ClassInfo*>(m_value & ~static_cast<uintptr_t>(1));
340         }
341         
342         const ClassInfo* getClassInfo() const
343         {
344             if (isEmpty())
345                 return 0;
346             if (isClassInfo())
347                 return asClassInfo();
348             return asStructure()->classInfo();
349         }
350         
351     private:
352         uintptr_t m_value;
353     };
354     
355     WeakBucket m_weakBuckets[numberOfBuckets]; // this is not covered by a write barrier because it is only set from GC
356 };
357
358 inline int getValueProfileBytecodeOffset(ValueProfile* valueProfile)
359 {
360     return valueProfile->m_bytecodeOffset;
361 }
362 #endif
363
364 }
365
366 #endif
367