1/*
2 * Copyright (C) 2008 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 SamplingTool_h
30#define SamplingTool_h
31
32#include <wtf/Assertions.h>
33#include <wtf/HashMap.h>
34#include <wtf/Threading.h>
35
36#include "Nodes.h"
37#include "Opcode.h"
38
39namespace JSC {
40
41 class ScriptExecutable;
42
43 class SamplingFlags {
44 friend class JIT;
45 public:
46 static void start();
47 static void stop();
48
49#if ENABLE(SAMPLING_FLAGS)
50 static void setFlag(unsigned flag)
51 {
52 ASSERT(flag >= 1);
53 ASSERT(flag <= 32);
54 s_flags |= 1u << (flag - 1);
55 }
56
57 static void clearFlag(unsigned flag)
58 {
59 ASSERT(flag >= 1);
60 ASSERT(flag <= 32);
61 s_flags &= ~(1u << (flag - 1));
62 }
63
64 static void sample();
65
66 class ScopedFlag {
67 public:
68 ScopedFlag(int flag)
69 : m_flag(flag)
70 {
71 setFlag(flag);
72 }
73
74 ~ScopedFlag()
75 {
76 clearFlag(m_flag);
77 }
78
79 private:
80 int m_flag;
81 };
82
83#endif
84 private:
85 static uint32_t s_flags;
86#if ENABLE(SAMPLING_FLAGS)
87 static uint64_t s_flagCounts[33];
88#endif
89 };
90
91 class CodeBlock;
92 class ExecState;
93 class Interpreter;
94 class ScopeNode;
95 struct Instruction;
96
97 struct ScriptSampleRecord {
98 ScriptSampleRecord(ScriptExecutable* executable)
99 : m_executable(executable)
100 , m_codeBlock(0)
101 , m_sampleCount(0)
102 , m_opcodeSampleCount(0)
103 , m_samples(0)
104 , m_size(0)
105 {
106 }
107
108 ~ScriptSampleRecord()
109 {
110 if (m_samples)
111 free(ptr: m_samples);
112 }
113
114 void sample(CodeBlock*, Instruction*);
115
116#if COMPILER(WINSCW) || COMPILER(ACC)
117 ScriptExecutable* m_executable;
118#else
119 RefPtr<ScriptExecutable> m_executable;
120#endif
121 CodeBlock* m_codeBlock;
122 int m_sampleCount;
123 int m_opcodeSampleCount;
124 int* m_samples;
125 unsigned m_size;
126 };
127
128 typedef WTF::HashMap<ScriptExecutable*, ScriptSampleRecord*> ScriptSampleRecordMap;
129
130 class SamplingThread {
131 public:
132 // Sampling thread state.
133 static bool s_running;
134 static unsigned s_hertz;
135 static ThreadIdentifier s_samplingThread;
136
137 static void start(unsigned hertz=10000);
138 static void stop();
139
140 static void* threadStartFunc(void*);
141 };
142
143 class SamplingTool {
144 public:
145 friend struct CallRecord;
146 friend class HostCallRecord;
147
148#if ENABLE(OPCODE_SAMPLING)
149 class CallRecord : public Noncopyable {
150 public:
151 CallRecord(SamplingTool* samplingTool)
152 : m_samplingTool(samplingTool)
153 , m_savedSample(samplingTool->m_sample)
154 , m_savedCodeBlock(samplingTool->m_codeBlock)
155 {
156 }
157
158 ~CallRecord()
159 {
160 m_samplingTool->m_sample = m_savedSample;
161 m_samplingTool->m_codeBlock = m_savedCodeBlock;
162 }
163
164 private:
165 SamplingTool* m_samplingTool;
166 intptr_t m_savedSample;
167 CodeBlock* m_savedCodeBlock;
168 };
169
170 class HostCallRecord : public CallRecord {
171 public:
172 HostCallRecord(SamplingTool* samplingTool)
173 : CallRecord(samplingTool)
174 {
175 samplingTool->m_sample |= 0x1;
176 }
177 };
178#else
179 class CallRecord : public Noncopyable {
180 public:
181 CallRecord(SamplingTool*)
182 {
183 }
184 };
185
186 class HostCallRecord : public CallRecord {
187 public:
188 HostCallRecord(SamplingTool* samplingTool)
189 : CallRecord(samplingTool)
190 {
191 }
192 };
193#endif
194
195 SamplingTool(Interpreter* interpreter)
196 : m_interpreter(interpreter)
197 , m_codeBlock(0)
198 , m_sample(0)
199 , m_sampleCount(0)
200 , m_opcodeSampleCount(0)
201#if ENABLE(CODEBLOCK_SAMPLING)
202 , m_scopeSampleMap(new ScriptSampleRecordMap())
203#endif
204 {
205 memset(s: m_opcodeSamples, c: 0, n: sizeof(m_opcodeSamples));
206 memset(s: m_opcodeSamplesInCTIFunctions, c: 0, n: sizeof(m_opcodeSamplesInCTIFunctions));
207 }
208
209 ~SamplingTool()
210 {
211#if ENABLE(CODEBLOCK_SAMPLING)
212 deleteAllValues(*m_scopeSampleMap);
213#endif
214 }
215
216 void setup();
217 void dump(ExecState*);
218
219 void notifyOfScope(ScriptExecutable* scope);
220
221 void sample(CodeBlock* codeBlock, Instruction* vPC)
222 {
223 ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3));
224 m_codeBlock = codeBlock;
225 m_sample = reinterpret_cast<intptr_t>(vPC);
226 }
227
228 CodeBlock** codeBlockSlot() { return &m_codeBlock; }
229 intptr_t* sampleSlot() { return &m_sample; }
230
231 void* encodeSample(Instruction* vPC, bool inCTIFunction = false, bool inHostFunction = false)
232 {
233 ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3));
234 return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(vPC) | (static_cast<intptr_t>(inCTIFunction) << 1) | static_cast<intptr_t>(inHostFunction));
235 }
236
237 static void sample();
238
239 private:
240 class Sample {
241 public:
242 Sample(volatile intptr_t sample, CodeBlock* volatile codeBlock)
243 : m_sample(sample)
244 , m_codeBlock(codeBlock)
245 {
246 }
247
248 bool isNull() { return !m_sample; }
249 CodeBlock* codeBlock() { return m_codeBlock; }
250 Instruction* vPC() { return reinterpret_cast<Instruction*>(m_sample & ~0x3); }
251 bool inHostFunction() { return m_sample & 0x1; }
252 bool inCTIFunction() { return m_sample & 0x2; }
253
254 private:
255 intptr_t m_sample;
256 CodeBlock* m_codeBlock;
257 };
258
259 void doRun();
260 static SamplingTool* s_samplingTool;
261
262 Interpreter* m_interpreter;
263
264 // State tracked by the main thread, used by the sampling thread.
265 CodeBlock* m_codeBlock;
266 intptr_t m_sample;
267
268 // Gathered sample data.
269 long long m_sampleCount;
270 long long m_opcodeSampleCount;
271 unsigned m_opcodeSamples[numOpcodeIDs];
272 unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs];
273
274#if ENABLE(CODEBLOCK_SAMPLING)
275 Mutex m_scriptSampleMapMutex;
276 OwnPtr<ScriptSampleRecordMap> m_scopeSampleMap;
277#endif
278 };
279
280 // AbstractSamplingCounter:
281 //
282 // Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
283 // See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
284 class AbstractSamplingCounter {
285 friend class JIT;
286 friend class DeletableSamplingCounter;
287 public:
288 void count(uint32_t count = 1)
289 {
290 m_counter += count;
291 }
292
293 static void dump();
294
295 protected:
296 // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
297 void init(const char* name)
298 {
299 m_counter = 0;
300 m_name = name;
301
302 // Set m_next to point to the head of the chain, and inform whatever is
303 // currently at the head that this node will now hold the pointer to it.
304 m_next = s_abstractSamplingCounterChain;
305 s_abstractSamplingCounterChain->m_referer = &m_next;
306 // Add this node to the head of the list.
307 s_abstractSamplingCounterChain = this;
308 m_referer = &s_abstractSamplingCounterChain;
309 }
310
311 int64_t m_counter;
312 const char* m_name;
313 AbstractSamplingCounter* m_next;
314 // This is a pointer to the pointer to this node in the chain; used to
315 // allow fast linked list deletion.
316 AbstractSamplingCounter** m_referer;
317 // Null object used to detect end of static chain.
318 static AbstractSamplingCounter s_abstractSamplingCounterChainEnd;
319 static AbstractSamplingCounter* s_abstractSamplingCounterChain;
320 static bool s_completed;
321 };
322
323#if ENABLE(SAMPLING_COUNTERS)
324 // SamplingCounter:
325 //
326 // This class is suitable and (hopefully!) convenient for cases where a counter is
327 // required within the scope of a single function. It can be instantiated as a
328 // static variable since it contains a constructor but not a destructor (static
329 // variables in WebKit cannot have destructors).
330 //
331 // For example:
332 //
333 // void someFunction()
334 // {
335 // static SamplingCounter countMe("This is my counter. There are many like it, but this one is mine.");
336 // countMe.count();
337 // // ...
338 // }
339 //
340 class SamplingCounter : public AbstractSamplingCounter {
341 public:
342 SamplingCounter(const char* name) { init(name); }
343 };
344
345 // GlobalSamplingCounter:
346 //
347 // This class is suitable for use where a counter is to be declared globally,
348 // since it contains neither a constructor nor destructor. Instead, ensure
349 // that 'name()' is called to provide the counter with a name (and also to
350 // allow it to be printed out on exit).
351 //
352 // GlobalSamplingCounter globalCounter;
353 //
354 // void firstFunction()
355 // {
356 // // Put this within a function that is definitely called!
357 // // (Or alternatively alongside all calls to 'count()').
358 // globalCounter.name("I Name You Destroyer.");
359 // globalCounter.count();
360 // // ...
361 // }
362 //
363 // void secondFunction()
364 // {
365 // globalCounter.count();
366 // // ...
367 // }
368 //
369 class GlobalSamplingCounter : public AbstractSamplingCounter {
370 public:
371 void name(const char* name)
372 {
373 // Global objects should be mapped in zero filled memory, so this should
374 // be a safe (albeit not necessarily threadsafe) check for 'first call'.
375 if (!m_next)
376 init(name);
377 }
378 };
379
380 // DeletableSamplingCounter:
381 //
382 // The above classes (SamplingCounter, GlobalSamplingCounter), are intended for
383 // use within a global or static scope, and as such cannot have a destructor.
384 // This means there is no convenient way for them to remove themselves from the
385 // static list of counters, and should an instance of either class be freed
386 // before 'dump()' has walked over the list it will potentially walk over an
387 // invalid pointer.
388 //
389 // This class is intended for use where the counter may possibly be deleted before
390 // the program exits. Should this occur, the counter will print it's value to
391 // stderr, and remove itself from the static list. Example:
392 //
393 // DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name");
394 // counter->count();
395 // delete counter;
396 //
397 class DeletableSamplingCounter : public AbstractSamplingCounter {
398 public:
399 DeletableSamplingCounter(const char* name) { init(name); }
400
401 ~DeletableSamplingCounter()
402 {
403 if (!s_completed)
404 fprintf(stderr, "DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter);
405 // Our m_referer pointer should know where the pointer to this node is,
406 // and m_next should know that this node is the previous node in the list.
407 ASSERT(*m_referer == this);
408 ASSERT(m_next->m_referer == &m_next);
409 // Remove this node from the list, and inform m_next that we have done so.
410 m_next->m_referer = m_referer;
411 *m_referer = m_next;
412 }
413 };
414#endif
415
416} // namespace JSC
417
418#endif // SamplingTool_h
419

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/bytecode/SamplingTool.h