michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef js_ProfilingStack_h michael@0: #define js_ProfilingStack_h michael@0: michael@0: #include "mozilla/NullPtr.h" michael@0: michael@0: #include "jsbytecode.h" michael@0: #include "jstypes.h" michael@0: michael@0: #include "js/Utility.h" michael@0: michael@0: struct JSRuntime; michael@0: michael@0: namespace js { michael@0: michael@0: // A call stack can be specified to the JS engine such that all JS entry/exits michael@0: // to functions push/pop an entry to/from the specified stack. michael@0: // michael@0: // For more detailed information, see vm/SPSProfiler.h. michael@0: // michael@0: class ProfileEntry michael@0: { michael@0: // All fields are marked volatile to prevent the compiler from re-ordering michael@0: // instructions. Namely this sequence: michael@0: // michael@0: // entry[size] = ...; michael@0: // size++; michael@0: // michael@0: // If the size modification were somehow reordered before the stores, then michael@0: // if a sample were taken it would be examining bogus information. michael@0: // michael@0: // A ProfileEntry represents both a C++ profile entry and a JS one. Both use michael@0: // the string as a description, but JS uses the sp as nullptr or (void*)1 to michael@0: // indicate that it is a JS entry. The script_ is then only ever examined for michael@0: // a JS entry, and the idx is used by both, but with different meanings. michael@0: // michael@0: const char * volatile string; // Descriptive string of this entry michael@0: void * volatile sp; // Relevant stack pointer for the entry, michael@0: // less than or equal to SCRIPT_OPT_STACKPOINTER for js michael@0: // script entries, greater for non-js entries. michael@0: JSScript * volatile script_; // if js(), non-null script which is running - low bit michael@0: // indicates if script is optimized or not. michael@0: int32_t volatile idx; // if js(), idx of pc, otherwise line number michael@0: michael@0: public: michael@0: static const uintptr_t SCRIPT_OPT_STACKPOINTER = 0x1; michael@0: michael@0: // All of these methods are marked with the 'volatile' keyword because SPS's michael@0: // representation of the stack is stored such that all ProfileEntry michael@0: // instances are volatile. These methods would not be available unless they michael@0: // were marked as volatile as well. michael@0: michael@0: bool js() const volatile { michael@0: MOZ_ASSERT_IF(uintptr_t(sp) <= SCRIPT_OPT_STACKPOINTER, script_ != nullptr); michael@0: return uintptr_t(sp) <= SCRIPT_OPT_STACKPOINTER; michael@0: } michael@0: michael@0: uint32_t line() const volatile { MOZ_ASSERT(!js()); return idx; } michael@0: JSScript *script() const volatile { MOZ_ASSERT(js()); return script_; } michael@0: bool scriptIsOptimized() const volatile { michael@0: MOZ_ASSERT(js()); michael@0: return uintptr_t(sp) <= SCRIPT_OPT_STACKPOINTER; michael@0: } michael@0: void *stackAddress() const volatile { michael@0: if (js()) michael@0: return nullptr; michael@0: return sp; michael@0: } michael@0: const char *label() const volatile { return string; } michael@0: michael@0: void setLine(uint32_t aLine) volatile { MOZ_ASSERT(!js()); idx = aLine; } michael@0: void setLabel(const char *aString) volatile { string = aString; } michael@0: void setStackAddress(void *aSp) volatile { sp = aSp; } michael@0: void setScript(JSScript *aScript) volatile { script_ = aScript; } michael@0: michael@0: // We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp. michael@0: JS_FRIEND_API(jsbytecode *) pc() const volatile; michael@0: JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile; michael@0: michael@0: static size_t offsetOfString() { return offsetof(ProfileEntry, string); } michael@0: static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); } michael@0: static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); } michael@0: static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); } michael@0: michael@0: // The index used in the entry can either be a line number or the offset of michael@0: // a pc into a script's code. To signify a nullptr pc, use a -1 index. This michael@0: // is checked against in pc() and setPC() to set/get the right pc. michael@0: static const int32_t NullPCIndex = -1; michael@0: michael@0: // This bit is added to the stack address to indicate that copying the michael@0: // frame label is not necessary when taking a sample of the pseudostack. michael@0: static const uintptr_t NoCopyBit = 1; michael@0: }; michael@0: michael@0: JS_FRIEND_API(void) michael@0: SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, michael@0: uint32_t max); michael@0: michael@0: JS_FRIEND_API(void) michael@0: EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled); michael@0: michael@0: JS_FRIEND_API(void) michael@0: RegisterRuntimeProfilingEventMarker(JSRuntime *rt, void (*fn)(const char *)); michael@0: michael@0: JS_FRIEND_API(jsbytecode*) michael@0: ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip); michael@0: michael@0: } // namespace js michael@0: michael@0: #endif /* js_ProfilingStack_h */