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