Bug 1057082 - Part 1 - Add profilingActivation linked list and refactor ProfilingFrameIterator. r=luke

This commit is contained in:
Kannan Vijayan 2014-08-26 14:03:04 -04:00
Родитель 872b0b7fbc
Коммит 7141c60325
7 изменённых файлов: 157 добавлений и 15 удалений

Просмотреть файл

@ -15,7 +15,11 @@
class JSAtom;
struct JSRuntime;
namespace js { class AsmJSActivation; class AsmJSProfilingFrameIterator; }
namespace js {
class Activation;
class AsmJSProfilingFrameIterator;
}
namespace JS {
@ -25,15 +29,15 @@ namespace JS {
// unwound.
class JS_PUBLIC_API(ProfilingFrameIterator)
{
js::AsmJSActivation *activation_;
js::Activation *activation_;
static const unsigned StorageSpace = 6 * sizeof(void*);
mozilla::AlignedStorage<StorageSpace> storage_;
js::AsmJSProfilingFrameIterator &iter() {
js::AsmJSProfilingFrameIterator &asmJSIter() {
JS_ASSERT(!done());
return *reinterpret_cast<js::AsmJSProfilingFrameIterator*>(storage_.addr());
}
const js::AsmJSProfilingFrameIterator &iter() const {
const js::AsmJSProfilingFrameIterator &asmJSIter() const {
JS_ASSERT(!done());
return *reinterpret_cast<const js::AsmJSProfilingFrameIterator*>(storage_.addr());
}
@ -64,6 +68,12 @@ class JS_PUBLIC_API(ProfilingFrameIterator)
// Return a label suitable for regexp-matching as performed by
// browser/devtools/profiler/cleopatra/js/parserWorker.js
const char *label() const;
private:
void iteratorConstruct(const RegisterState &state);
void iteratorConstruct();
void iteratorDestroy();
bool iteratorDone();
};
} // namespace JS

Просмотреть файл

@ -267,6 +267,10 @@ class ForkJoinActivation : public Activation
public:
explicit ForkJoinActivation(JSContext *cx);
~ForkJoinActivation();
bool isProfiling() const {
return false;
}
};
class ForkJoinContext;

Просмотреть файл

@ -78,6 +78,7 @@ PerThreadData::PerThreadData(JSRuntime *runtime)
traceLogger(nullptr),
#endif
activation_(nullptr),
profilingActivation_(nullptr),
asmJSActivationStack_(nullptr),
autoFlushICache_(nullptr),
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)

Просмотреть файл

@ -567,6 +567,12 @@ class PerThreadData : public PerThreadDataFriendFields
*/
js::Activation *activation_;
/*
* Points to the most recent profiling activation running on the
* thread. Protected by rt->interruptLock.
*/
js::Activation * volatile profilingActivation_;
/* See AsmJSActivation comment. Protected by rt->interruptLock. */
js::AsmJSActivation * volatile asmJSActivationStack_;
@ -589,6 +595,10 @@ class PerThreadData : public PerThreadDataFriendFields
return offsetof(PerThreadData, activation_);
}
js::Activation *profilingActivation() const {
return profilingActivation_;
}
js::AsmJSActivation *asmJSActivationStack() const {
return asmJSActivationStack_;
}

Просмотреть файл

@ -738,11 +738,16 @@ Activation::Activation(ThreadSafeContext *cx, Kind kind)
: cx_(cx),
compartment_(cx->compartment_),
prev_(cx->perThreadData->activation_),
prevProfiling_(prev_ ? prev_->mostRecentProfiling() : nullptr),
savedFrameChain_(0),
hideScriptedCallerCount_(0),
kind_(kind)
{
cx->perThreadData->activation_ = this;
// Link the activation into the list of profiling activations if needed.
if (isProfiling())
registerProfiling();
}
Activation::~Activation()
@ -750,6 +755,33 @@ Activation::~Activation()
JS_ASSERT(cx_->perThreadData->activation_ == this);
JS_ASSERT(hideScriptedCallerCount_ == 0);
cx_->perThreadData->activation_ = prev_;
if (isProfiling())
unregisterProfiling();
}
bool
Activation::isProfiling() const
{
if (isInterpreter())
return asInterpreter()->isProfiling();
if (isJit())
return asJit()->isProfiling();
if (isForkJoin())
return asForkJoin()->isProfiling();
JS_ASSERT(isAsmJS());
return asAsmJS()->isProfiling();
}
Activation *
Activation::mostRecentProfiling()
{
if (isProfiling())
return this;
return prevProfiling_;
}
InterpreterActivation::InterpreterActivation(RunState &state, JSContext *cx,

Просмотреть файл

@ -1618,6 +1618,23 @@ InterpreterFrameIterator::operator++()
return *this;
}
void
Activation::registerProfiling()
{
JS_ASSERT(isProfiling());
JSRuntime::AutoLockForInterrupt lock(cx_->asJSContext()->runtime());
cx_->perThreadData->profilingActivation_ = this;
}
void
Activation::unregisterProfiling()
{
JS_ASSERT(isProfiling());
JSRuntime::AutoLockForInterrupt lock(cx_->asJSContext()->runtime());
JS_ASSERT(cx_->perThreadData->profilingActivation_ == this);
cx_->perThreadData->profilingActivation_ = prevProfiling_;
}
ActivationIterator::ActivationIterator(JSRuntime *rt)
: jitTop_(rt->mainThread.jitTop),
activation_(rt->mainThread.activation_)
@ -1653,50 +1670,99 @@ ActivationIterator::settle()
}
JS::ProfilingFrameIterator::ProfilingFrameIterator(JSRuntime *rt, const RegisterState &state)
: activation_(rt->mainThread.asmJSActivationStack())
: activation_(rt->mainThread.profilingActivation())
{
if (!activation_)
return;
JS_ASSERT(activation_->isProfiling());
static_assert(sizeof(AsmJSProfilingFrameIterator) <= StorageSpace, "Need to increase storage");
new (storage_.addr()) AsmJSProfilingFrameIterator(*activation_, state);
iteratorConstruct(state);
settle();
}
JS::ProfilingFrameIterator::~ProfilingFrameIterator()
{
if (!done())
iter().~AsmJSProfilingFrameIterator();
if (!done()) {
JS_ASSERT(activation_->isProfiling());
iteratorDestroy();
}
}
void
JS::ProfilingFrameIterator::operator++()
{
JS_ASSERT(!done());
++iter();
JS_ASSERT(activation_->isAsmJS());
++asmJSIter();
settle();
}
void
JS::ProfilingFrameIterator::settle()
{
while (iter().done()) {
iter().~AsmJSProfilingFrameIterator();
activation_ = activation_->prevAsmJS();
while (iteratorDone()) {
iteratorDestroy();
activation_ = activation_->prevProfiling();
if (!activation_)
return;
new (storage_.addr()) AsmJSProfilingFrameIterator(*activation_);
iteratorConstruct();
}
}
void
JS::ProfilingFrameIterator::iteratorConstruct(const RegisterState &state)
{
JS_ASSERT(!done());
JS_ASSERT(activation_->isAsmJS());
new (storage_.addr()) AsmJSProfilingFrameIterator(*activation_->asAsmJS(), state);
}
void
JS::ProfilingFrameIterator::iteratorConstruct()
{
JS_ASSERT(!done());
JS_ASSERT(activation_->isAsmJS());
new (storage_.addr()) AsmJSProfilingFrameIterator(*activation_->asAsmJS());
}
void
JS::ProfilingFrameIterator::iteratorDestroy()
{
JS_ASSERT(!done());
JS_ASSERT(activation_->isAsmJS());
asmJSIter().~AsmJSProfilingFrameIterator();
}
bool
JS::ProfilingFrameIterator::iteratorDone()
{
JS_ASSERT(!done());
JS_ASSERT(activation_->isAsmJS());
return asmJSIter().done();
}
void *
JS::ProfilingFrameIterator::stackAddress() const
{
return iter().stackAddress();
JS_ASSERT(!done());
JS_ASSERT(activation_->isAsmJS());
return asmJSIter().stackAddress();
}
const char *
JS::ProfilingFrameIterator::label() const
{
return iter().label();
JS_ASSERT(!done());
JS_ASSERT(activation_->isAsmJS());
return asmJSIter().label();
}

Просмотреть файл

@ -1103,6 +1103,7 @@ class Activation
ThreadSafeContext *cx_;
JSCompartment *compartment_;
Activation *prev_;
Activation *prevProfiling_;
// Counter incremented by JS_SaveFrameChain on the top-most activation and
// decremented by JS_RestoreFrameChain. If > 0, ScriptFrameIter should stop
@ -1133,6 +1134,8 @@ class Activation
Activation *prev() const {
return prev_;
}
Activation *prevProfiling() const { return prevProfiling_; }
inline Activation *mostRecentProfiling();
bool isInterpreter() const {
return kind_ == Interpreter;
@ -1147,6 +1150,10 @@ class Activation
return kind_ == AsmJS;
}
inline bool isProfiling() const;
void registerProfiling();
void unregisterProfiling();
InterpreterActivation *asInterpreter() const {
JS_ASSERT(isInterpreter());
return (InterpreterActivation *)this;
@ -1238,6 +1245,10 @@ class InterpreterActivation : public Activation
return opMask_;
}
bool isProfiling() const {
return false;
}
// If this js::Interpret frame is running |script|, enable interrupts.
void enableInterruptsIfRunning(JSScript *script) {
if (regs_.fp()->script() == script)
@ -1323,6 +1334,10 @@ class JitActivation : public Activation
}
void setActive(JSContext *cx, bool active = true);
bool isProfiling() const {
return false;
}
uint8_t *prevJitTop() const {
return prevJitTop_;
}
@ -1481,6 +1496,10 @@ class AsmJSActivation : public Activation
AsmJSModule &module() const { return module_; }
AsmJSActivation *prevAsmJS() const { return prevAsmJS_; }
bool isProfiling() const {
return true;
}
// Returns a pointer to the base of the innermost stack frame of asm.js code
// in this activation.
uint8_t *fp() const { return fp_; }