| |
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| |
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
| |
3 * This Source Code Form is subject to the terms of the Mozilla Public |
| |
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
| |
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
6 |
| |
7 #ifndef js_ProfilingStack_h |
| |
8 #define js_ProfilingStack_h |
| |
9 |
| |
10 #include "mozilla/NullPtr.h" |
| |
11 |
| |
12 #include "jsbytecode.h" |
| |
13 #include "jstypes.h" |
| |
14 |
| |
15 #include "js/Utility.h" |
| |
16 |
| |
17 struct JSRuntime; |
| |
18 |
| |
19 namespace js { |
| |
20 |
| |
21 // A call stack can be specified to the JS engine such that all JS entry/exits |
| |
22 // to functions push/pop an entry to/from the specified stack. |
| |
23 // |
| |
24 // For more detailed information, see vm/SPSProfiler.h. |
| |
25 // |
| |
26 class ProfileEntry |
| |
27 { |
| |
28 // All fields are marked volatile to prevent the compiler from re-ordering |
| |
29 // instructions. Namely this sequence: |
| |
30 // |
| |
31 // entry[size] = ...; |
| |
32 // size++; |
| |
33 // |
| |
34 // If the size modification were somehow reordered before the stores, then |
| |
35 // if a sample were taken it would be examining bogus information. |
| |
36 // |
| |
37 // A ProfileEntry represents both a C++ profile entry and a JS one. Both use |
| |
38 // the string as a description, but JS uses the sp as nullptr or (void*)1 to |
| |
39 // indicate that it is a JS entry. The script_ is then only ever examined for |
| |
40 // a JS entry, and the idx is used by both, but with different meanings. |
| |
41 // |
| |
42 const char * volatile string; // Descriptive string of this entry |
| |
43 void * volatile sp; // Relevant stack pointer for the entry, |
| |
44 // less than or equal to SCRIPT_OPT_STACKPOINTER for js |
| |
45 // script entries, greater for non-js entries. |
| |
46 JSScript * volatile script_; // if js(), non-null script which is running - low bit |
| |
47 // indicates if script is optimized or not. |
| |
48 int32_t volatile idx; // if js(), idx of pc, otherwise line number |
| |
49 |
| |
50 public: |
| |
51 static const uintptr_t SCRIPT_OPT_STACKPOINTER = 0x1; |
| |
52 |
| |
53 // All of these methods are marked with the 'volatile' keyword because SPS's |
| |
54 // representation of the stack is stored such that all ProfileEntry |
| |
55 // instances are volatile. These methods would not be available unless they |
| |
56 // were marked as volatile as well. |
| |
57 |
| |
58 bool js() const volatile { |
| |
59 MOZ_ASSERT_IF(uintptr_t(sp) <= SCRIPT_OPT_STACKPOINTER, script_ != nullptr); |
| |
60 return uintptr_t(sp) <= SCRIPT_OPT_STACKPOINTER; |
| |
61 } |
| |
62 |
| |
63 uint32_t line() const volatile { MOZ_ASSERT(!js()); return idx; } |
| |
64 JSScript *script() const volatile { MOZ_ASSERT(js()); return script_; } |
| |
65 bool scriptIsOptimized() const volatile { |
| |
66 MOZ_ASSERT(js()); |
| |
67 return uintptr_t(sp) <= SCRIPT_OPT_STACKPOINTER; |
| |
68 } |
| |
69 void *stackAddress() const volatile { |
| |
70 if (js()) |
| |
71 return nullptr; |
| |
72 return sp; |
| |
73 } |
| |
74 const char *label() const volatile { return string; } |
| |
75 |
| |
76 void setLine(uint32_t aLine) volatile { MOZ_ASSERT(!js()); idx = aLine; } |
| |
77 void setLabel(const char *aString) volatile { string = aString; } |
| |
78 void setStackAddress(void *aSp) volatile { sp = aSp; } |
| |
79 void setScript(JSScript *aScript) volatile { script_ = aScript; } |
| |
80 |
| |
81 // We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp. |
| |
82 JS_FRIEND_API(jsbytecode *) pc() const volatile; |
| |
83 JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile; |
| |
84 |
| |
85 static size_t offsetOfString() { return offsetof(ProfileEntry, string); } |
| |
86 static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); } |
| |
87 static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); } |
| |
88 static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); } |
| |
89 |
| |
90 // The index used in the entry can either be a line number or the offset of |
| |
91 // a pc into a script's code. To signify a nullptr pc, use a -1 index. This |
| |
92 // is checked against in pc() and setPC() to set/get the right pc. |
| |
93 static const int32_t NullPCIndex = -1; |
| |
94 |
| |
95 // This bit is added to the stack address to indicate that copying the |
| |
96 // frame label is not necessary when taking a sample of the pseudostack. |
| |
97 static const uintptr_t NoCopyBit = 1; |
| |
98 }; |
| |
99 |
| |
100 JS_FRIEND_API(void) |
| |
101 SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, |
| |
102 uint32_t max); |
| |
103 |
| |
104 JS_FRIEND_API(void) |
| |
105 EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled); |
| |
106 |
| |
107 JS_FRIEND_API(void) |
| |
108 RegisterRuntimeProfilingEventMarker(JSRuntime *rt, void (*fn)(const char *)); |
| |
109 |
| |
110 JS_FRIEND_API(jsbytecode*) |
| |
111 ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip); |
| |
112 |
| |
113 } // namespace js |
| |
114 |
| |
115 #endif /* js_ProfilingStack_h */ |