зеркало из https://github.com/mozilla/gecko-dev.git
Bug 778979 - Part 4: Provide an ip => pc translation mechanism for currently running JIT code. r=bhackett
This commit is contained in:
Родитель
0603f5b88e
Коммит
b4ee1d6c18
|
@ -922,6 +922,12 @@ EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled)
|
||||||
rt->spsProfiler.enable(enabled);
|
rt->spsProfiler.enable(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_FRIEND_API(jsbytecode*)
|
||||||
|
ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip)
|
||||||
|
{
|
||||||
|
return rt->spsProfiler.ipToPC(script, size_t(ip));
|
||||||
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks)
|
SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks)
|
||||||
{
|
{
|
||||||
|
|
|
@ -614,6 +614,9 @@ SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
|
EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
|
||||||
|
|
||||||
|
JS_FRIEND_API(jsbytecode*)
|
||||||
|
ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip);
|
||||||
|
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JS_FRIEND_API(void *)
|
JS_FRIEND_API(void *)
|
||||||
GetOwnerThread(const JSContext *cx);
|
GetOwnerThread(const JSContext *cx);
|
||||||
|
|
|
@ -40,182 +40,48 @@ const char Probes::anonymousName[] = "(anonymous)";
|
||||||
|
|
||||||
bool Probes::ProfilingActive = true;
|
bool Probes::ProfilingActive = true;
|
||||||
|
|
||||||
static Vector<Probes::JITWatcher*, 4, SystemAllocPolicy> jitWatchers;
|
|
||||||
|
|
||||||
bool
|
|
||||||
Probes::addJITWatcher(JITWatcher *watcher)
|
|
||||||
{
|
|
||||||
return jitWatchers.append(watcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Probes::removeJITWatcher(JSRuntime *rt, JITWatcher *watcher)
|
|
||||||
{
|
|
||||||
JITWatcher **place = Find(jitWatchers, watcher);
|
|
||||||
if (!place)
|
|
||||||
return false;
|
|
||||||
if (rt)
|
|
||||||
rt->delete_(*place);
|
|
||||||
else
|
|
||||||
Foreground::delete_(*place);
|
|
||||||
jitWatchers.erase(place);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Probes::removeAllJITWatchers(JSRuntime *rt)
|
|
||||||
{
|
|
||||||
if (rt) {
|
|
||||||
for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p)
|
|
||||||
rt->delete_(*p);
|
|
||||||
} else {
|
|
||||||
for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p)
|
|
||||||
Foreground::delete_(*p);
|
|
||||||
}
|
|
||||||
jitWatchers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
Probes::JITReportGranularity
|
Probes::JITReportGranularity
|
||||||
Probes::JITGranularityRequested()
|
Probes::JITGranularityRequested(JSContext *cx)
|
||||||
{
|
{
|
||||||
JITReportGranularity want = JITREPORT_GRANULARITY_NONE;
|
if (cx->runtime->spsProfiler.enabled())
|
||||||
for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) {
|
return JITREPORT_GRANULARITY_LINE;
|
||||||
JITReportGranularity request = (*p)->granularityRequested();
|
return JITREPORT_GRANULARITY_NONE;
|
||||||
if (request > want)
|
|
||||||
want = request;
|
|
||||||
}
|
|
||||||
|
|
||||||
return want;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
/*
|
|
||||||
* Flatten the tree of inlined frames into a series of native code regions, one
|
|
||||||
* for each contiguous section of native code that belongs to a single
|
|
||||||
* ActiveFrame. (Note that some of these regions may be zero-length, for
|
|
||||||
* example if two ActiveFrames end at the same place.)
|
|
||||||
*/
|
|
||||||
typedef mjit::Compiler::ActiveFrame ActiveFrame;
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Probes::JITWatcher::CollectNativeRegions(RegionVector ®ions,
|
|
||||||
JSRuntime *rt,
|
|
||||||
mjit::JITChunk *jit,
|
|
||||||
mjit::JSActiveFrame *outerFrame,
|
|
||||||
mjit::JSActiveFrame **inlineFrames)
|
|
||||||
{
|
|
||||||
regions.resize(jit->nInlineFrames * 2 + 2);
|
|
||||||
|
|
||||||
mjit::JSActiveFrame **stack =
|
|
||||||
rt->array_new<mjit::JSActiveFrame*>(jit->nInlineFrames+2);
|
|
||||||
if (!stack)
|
|
||||||
return false;
|
|
||||||
uint32_t depth = 0;
|
|
||||||
uint32_t ip = 0;
|
|
||||||
|
|
||||||
stack[depth++] = NULL;
|
|
||||||
stack[depth++] = outerFrame;
|
|
||||||
regions[0].frame = outerFrame;
|
|
||||||
regions[0].script = outerFrame->script;
|
|
||||||
regions[0].pc = outerFrame->script->code;
|
|
||||||
regions[0].enter = true;
|
|
||||||
ip++;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i <= jit->nInlineFrames; i++) {
|
|
||||||
mjit::JSActiveFrame *frame = (i < jit->nInlineFrames) ? inlineFrames[i] : outerFrame;
|
|
||||||
|
|
||||||
// Not a down frame; pop the current frame, then pop until we reach
|
|
||||||
// this frame's parent, recording subframe ends as we go
|
|
||||||
while (stack[depth-1] != frame->parent) {
|
|
||||||
depth--;
|
|
||||||
JS_ASSERT(depth > 0);
|
|
||||||
// Pop up from regions[ip-1].frame to top of the stack: start a
|
|
||||||
// region in the destination frame and close off the source
|
|
||||||
// (origin) frame at the end of its script
|
|
||||||
mjit::JSActiveFrame *src = regions[ip-1].frame;
|
|
||||||
mjit::JSActiveFrame *dst = stack[depth-1];
|
|
||||||
JS_ASSERT_IF(!dst, i == jit->nInlineFrames);
|
|
||||||
regions[ip].frame = dst;
|
|
||||||
regions[ip].script = dst ? dst->script : NULL;
|
|
||||||
regions[ip].pc = src->parentPC + 1;
|
|
||||||
regions[ip-1].endpc = src->script->code + src->script->length;
|
|
||||||
regions[ip].enter = false;
|
|
||||||
ip++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < jit->nInlineFrames) {
|
|
||||||
// Push a frame (enter an inlined function). Start a region at the
|
|
||||||
// beginning of the new frame's script, and end the previous region
|
|
||||||
// at parentPC.
|
|
||||||
stack[depth++] = frame;
|
|
||||||
|
|
||||||
regions[ip].frame = frame;
|
|
||||||
regions[ip].script = frame->script;
|
|
||||||
regions[ip].pc = frame->script->code;
|
|
||||||
regions[ip-1].endpc = frame->parentPC;
|
|
||||||
regions[ip].enter = true;
|
|
||||||
ip++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final region is always zero-length and not particularly useful
|
|
||||||
ip--;
|
|
||||||
regions.popBack();
|
|
||||||
|
|
||||||
mjit::JSActiveFrame *prev = NULL;
|
|
||||||
for (NativeRegion *iter = regions.begin(); iter != regions.end(); ++iter) {
|
|
||||||
mjit::JSActiveFrame *frame = iter->frame;
|
|
||||||
if (iter->enter) {
|
|
||||||
// Pushing down a frame, so region starts at the beginning of the
|
|
||||||
// (destination) frame
|
|
||||||
iter->mainOffset = frame->mainCodeStart;
|
|
||||||
iter->stubOffset = frame->stubCodeStart;
|
|
||||||
} else {
|
|
||||||
// Popping up a level, so region starts at the end of the (source) frame
|
|
||||||
iter->mainOffset = prev->mainCodeEnd;
|
|
||||||
iter->stubOffset = prev->stubCodeEnd;
|
|
||||||
}
|
|
||||||
prev = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ASSERT(ip == 2 * jit->nInlineFrames + 1);
|
|
||||||
rt->array_delete(stack);
|
|
||||||
|
|
||||||
// All of the stub code comes immediately after the main code
|
|
||||||
for (NativeRegion *iter = regions.begin(); iter != regions.end(); ++iter)
|
|
||||||
iter->stubOffset += outerFrame->mainCodeEnd;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Probes::registerMJITCode(JSContext *cx, js::mjit::JITChunk *chunk,
|
Probes::registerMJITCode(JSContext *cx, js::mjit::JITChunk *chunk,
|
||||||
js::mjit::JSActiveFrame *outerFrame,
|
js::mjit::JSActiveFrame *outerFrame,
|
||||||
js::mjit::JSActiveFrame **inlineFrames,
|
js::mjit::JSActiveFrame **inlineFrames)
|
||||||
void *mainCodeAddress, size_t mainCodeSize,
|
|
||||||
void *stubCodeAddress, size_t stubCodeSize)
|
|
||||||
{
|
{
|
||||||
for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p)
|
if (cx->runtime->spsProfiler.enabled() &&
|
||||||
(*p)->registerMJITCode(cx, chunk, outerFrame,
|
!cx->runtime->spsProfiler.registerMJITCode(chunk, outerFrame, inlineFrames))
|
||||||
inlineFrames,
|
{
|
||||||
mainCodeAddress, mainCodeSize,
|
return false;
|
||||||
stubCodeAddress, stubCodeSize);
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Probes::discardMJITCode(FreeOp *fop, mjit::JITScript *jscr, mjit::JITChunk *chunk, void* address)
|
Probes::discardMJITCode(FreeOp *fop, mjit::JITScript *jscr, mjit::JITChunk *chunk, void* address)
|
||||||
{
|
{
|
||||||
for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p)
|
if (fop->runtime()->spsProfiler.enabled())
|
||||||
(*p)->discardMJITCode(fop, jscr, chunk, address);
|
fop->runtime()->spsProfiler.discardMJITCode(jscr, chunk, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
Probes::registerICCode(JSContext *cx,
|
Probes::registerICCode(JSContext *cx,
|
||||||
mjit::JITChunk *chunk, JSScript *script, jsbytecode* pc,
|
mjit::JITChunk *chunk, JSScript *script, jsbytecode* pc,
|
||||||
void *start, size_t size)
|
void *start, size_t size)
|
||||||
{
|
{
|
||||||
for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p)
|
if (cx->runtime->spsProfiler.enabled() &&
|
||||||
(*p)->registerICCode(cx, chunk, script, pc, start, size);
|
!cx->runtime->spsProfiler.registerICCode(chunk, script, pc, start, size))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -223,8 +89,10 @@ Probes::registerICCode(JSContext *cx,
|
||||||
void
|
void
|
||||||
Probes::discardExecutableRegion(void *start, size_t size)
|
Probes::discardExecutableRegion(void *start, size_t size)
|
||||||
{
|
{
|
||||||
for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p)
|
/*
|
||||||
(*p)->discardExecutableRegion(start, size);
|
* Not needed for SPS because ICs are disposed of when the normal JITChunk
|
||||||
|
* is disposed of
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSRuntime *initRuntime;
|
static JSRuntime *initRuntime;
|
||||||
|
@ -276,8 +144,6 @@ Probes::shutdown()
|
||||||
ok = false;
|
ok = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Probes::removeAllJITWatchers(NULL);
|
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,88 +197,20 @@ enum JITReportGranularity {
|
||||||
JITREPORT_GRANULARITY_OP = 3
|
JITREPORT_GRANULARITY_OP = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Observer class for JIT code allocation/deallocation. Currently, this only
|
|
||||||
* handles the method JIT, and does not get notifications when JIT code is
|
|
||||||
* changed (patched) with no new allocation.
|
|
||||||
*/
|
|
||||||
class JITWatcher {
|
|
||||||
public:
|
|
||||||
struct NativeRegion {
|
|
||||||
mjit::JSActiveFrame *frame;
|
|
||||||
JSScript *script;
|
|
||||||
size_t inlinedOffset;
|
|
||||||
jsbytecode *pc;
|
|
||||||
jsbytecode *endpc;
|
|
||||||
uintptr_t mainOffset;
|
|
||||||
uintptr_t stubOffset;
|
|
||||||
bool enter;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Vector<NativeRegion, 0, RuntimeAllocPolicy> RegionVector;
|
|
||||||
|
|
||||||
virtual JITReportGranularity granularityRequested() = 0;
|
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
|
||||||
static bool CollectNativeRegions(RegionVector ®ions,
|
|
||||||
JSRuntime *rt,
|
|
||||||
mjit::JITChunk *jit,
|
|
||||||
mjit::JSActiveFrame *outerFrame,
|
|
||||||
mjit::JSActiveFrame **inlineFrames);
|
|
||||||
|
|
||||||
virtual void registerMJITCode(JSContext *cx, js::mjit::JITChunk *chunk,
|
|
||||||
mjit::JSActiveFrame *outerFrame,
|
|
||||||
mjit::JSActiveFrame **inlineFrames,
|
|
||||||
void *mainCodeAddress, size_t mainCodeSize,
|
|
||||||
void *stubCodeAddress, size_t stubCodeSize) = 0;
|
|
||||||
|
|
||||||
virtual void discardMJITCode(FreeOp *fop, mjit::JITScript *jscr, mjit::JITChunk *chunk,
|
|
||||||
void* address) = 0;
|
|
||||||
|
|
||||||
virtual void registerICCode(JSContext *cx,
|
|
||||||
js::mjit::JITChunk *chunk, JSScript *script, jsbytecode* pc,
|
|
||||||
void *start, size_t size) = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
virtual void discardExecutableRegion(void *start, size_t size) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Register a JITWatcher subclass to be informed of JIT code
|
|
||||||
* allocation/deallocation.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
addJITWatcher(JITWatcher *watcher);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove (and destroy) a registered JITWatcher. rt may be NULL. Returns false
|
|
||||||
* if the watcher is not found.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
removeJITWatcher(JSRuntime *rt, JITWatcher *watcher);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove (and destroy) all registered JITWatchers. rt may be NULL.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
removeAllJITWatchers(JSRuntime *rt);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finest granularity of JIT information desired by all watchers.
|
* Finest granularity of JIT information desired by all watchers.
|
||||||
*/
|
*/
|
||||||
JITReportGranularity
|
JITReportGranularity
|
||||||
JITGranularityRequested();
|
JITGranularityRequested(JSContext *cx);
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
/*
|
/*
|
||||||
* New method JIT code has been created
|
* New method JIT code has been created
|
||||||
*/
|
*/
|
||||||
void
|
bool
|
||||||
registerMJITCode(JSContext *cx, js::mjit::JITChunk *chunk,
|
registerMJITCode(JSContext *cx, js::mjit::JITChunk *chunk,
|
||||||
mjit::JSActiveFrame *outerFrame,
|
mjit::JSActiveFrame *outerFrame,
|
||||||
mjit::JSActiveFrame **inlineFrames,
|
mjit::JSActiveFrame **inlineFrames);
|
||||||
void *mainCodeAddress, size_t mainCodeSize,
|
|
||||||
void *stubCodeAddress, size_t stubCodeSize);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method JIT code is about to be discarded
|
* Method JIT code is about to be discarded
|
||||||
|
@ -289,7 +221,7 @@ discardMJITCode(FreeOp *fop, mjit::JITScript *jscr, mjit::JITChunk *chunk, void*
|
||||||
/*
|
/*
|
||||||
* IC code has been allocated within the given JITChunk
|
* IC code has been allocated within the given JITChunk
|
||||||
*/
|
*/
|
||||||
void
|
bool
|
||||||
registerICCode(JSContext *cx,
|
registerICCode(JSContext *cx,
|
||||||
mjit::JITChunk *chunk, JSScript *script, jsbytecode* pc,
|
mjit::JITChunk *chunk, JSScript *script, jsbytecode* pc,
|
||||||
void *start, size_t size);
|
void *start, size_t size);
|
||||||
|
@ -376,7 +308,7 @@ inline bool
|
||||||
Probes::wantNativeAddressInfo(JSContext *cx)
|
Probes::wantNativeAddressInfo(JSContext *cx)
|
||||||
{
|
{
|
||||||
return (cx->reportGranularity >= JITREPORT_GRANULARITY_FUNCTION &&
|
return (cx->reportGranularity >= JITREPORT_GRANULARITY_FUNCTION &&
|
||||||
JITGranularityRequested() >= JITREPORT_GRANULARITY_FUNCTION);
|
JITGranularityRequested(cx) >= JITREPORT_GRANULARITY_FUNCTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
|
|
|
@ -178,6 +178,8 @@ class SPSInstrumentation {
|
||||||
* reenter() will be a no-op.
|
* reenter() will be a no-op.
|
||||||
*/
|
*/
|
||||||
void skipNextReenter() {
|
void skipNextReenter() {
|
||||||
|
if (!enabled())
|
||||||
|
return;
|
||||||
JS_ASSERT(!frame->skipNext && frame->left == 0);
|
JS_ASSERT(!frame->skipNext && frame->left == 0);
|
||||||
frame->skipNext = true;
|
frame->skipNext = true;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +190,8 @@ class SPSInstrumentation {
|
||||||
* that further instrumentation should actually be emitted.
|
* that further instrumentation should actually be emitted.
|
||||||
*/
|
*/
|
||||||
void setPushed() {
|
void setPushed() {
|
||||||
|
if (!enabled())
|
||||||
|
return;
|
||||||
JS_ASSERT(!frame->pushed);
|
JS_ASSERT(!frame->pushed);
|
||||||
frame->pushed = true;
|
frame->pushed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1777,11 +1777,17 @@ mjit::Compiler::finishThisUp()
|
||||||
JSC::ExecutableAllocator::makeExecutable(result, masm.size() + stubcc.size());
|
JSC::ExecutableAllocator::makeExecutable(result, masm.size() + stubcc.size());
|
||||||
JSC::ExecutableAllocator::cacheFlush(result, masm.size() + stubcc.size());
|
JSC::ExecutableAllocator::cacheFlush(result, masm.size() + stubcc.size());
|
||||||
|
|
||||||
Probes::registerMJITCode(cx, chunk,
|
a->mainCodeStart = size_t(result);
|
||||||
a,
|
a->mainCodeEnd = size_t(result + masm.size());
|
||||||
(JSActiveFrame**) inlineFrames.begin(),
|
a->stubCodeStart = a->mainCodeEnd;
|
||||||
result, masm.size(),
|
a->stubCodeEnd = a->mainCodeEnd + stubcc.size();
|
||||||
result + masm.size(), stubcc.size());
|
if (!Probes::registerMJITCode(cx, chunk,
|
||||||
|
a, (JSActiveFrame**) inlineFrames.begin())) {
|
||||||
|
execPool->release();
|
||||||
|
cx->free_(chunk);
|
||||||
|
js_ReportOutOfMemory(cx);
|
||||||
|
return Compile_Error;
|
||||||
|
}
|
||||||
|
|
||||||
outerChunkRef().chunk = chunk;
|
outerChunkRef().chunk = chunk;
|
||||||
|
|
||||||
|
@ -2050,7 +2056,7 @@ mjit::Compiler::generateMethod()
|
||||||
/* Track this sync code for the previous op. */
|
/* Track this sync code for the previous op. */
|
||||||
size_t length = masm.size() - masm.distanceOf(start);
|
size_t length = masm.size() - masm.distanceOf(start);
|
||||||
uint32_t offset = ssa.frameLength(a->inlineIndex) + lastPC - script->code;
|
uint32_t offset = ssa.frameLength(a->inlineIndex) + lastPC - script->code;
|
||||||
pcLengths[offset].codeLength += length;
|
pcLengths[offset].codeLengthAugment += length;
|
||||||
}
|
}
|
||||||
JS_ASSERT(frame.consistentRegisters(PC));
|
JS_ASSERT(frame.consistentRegisters(PC));
|
||||||
}
|
}
|
||||||
|
@ -2136,7 +2142,8 @@ mjit::Compiler::generateMethod()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Label codeStart = masm.label();
|
Label inlineStart = masm.label();
|
||||||
|
Label stubStart = stubcc.masm.label();
|
||||||
bool countsUpdated = false;
|
bool countsUpdated = false;
|
||||||
bool arithUpdated = false;
|
bool arithUpdated = false;
|
||||||
|
|
||||||
|
@ -2167,7 +2174,7 @@ mjit::Compiler::generateMethod()
|
||||||
* as we want to skip updating for ops we didn't generate any code for.
|
* as we want to skip updating for ops we didn't generate any code for.
|
||||||
*/
|
*/
|
||||||
if (script->hasScriptCounts && JOF_OPTYPE(op) == JOF_JUMP)
|
if (script->hasScriptCounts && JOF_OPTYPE(op) == JOF_JUMP)
|
||||||
updatePCCounts(PC, &codeStart, &countsUpdated);
|
updatePCCounts(PC, &countsUpdated);
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* BEGIN COMPILER OPS *
|
* BEGIN COMPILER OPS *
|
||||||
|
@ -2203,7 +2210,7 @@ mjit::Compiler::generateMethod()
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_RETURN)
|
BEGIN_CASE(JSOP_RETURN)
|
||||||
if (script->hasScriptCounts)
|
if (script->hasScriptCounts)
|
||||||
updatePCCounts(PC, &codeStart, &countsUpdated);
|
updatePCCounts(PC, &countsUpdated);
|
||||||
emitReturn(frame.peek(-1));
|
emitReturn(frame.peek(-1));
|
||||||
fallthrough = false;
|
fallthrough = false;
|
||||||
END_CASE(JSOP_RETURN)
|
END_CASE(JSOP_RETURN)
|
||||||
|
@ -2357,7 +2364,7 @@ mjit::Compiler::generateMethod()
|
||||||
jsbytecode *target = NULL;
|
jsbytecode *target = NULL;
|
||||||
if (fused != JSOP_NOP) {
|
if (fused != JSOP_NOP) {
|
||||||
if (script->hasScriptCounts)
|
if (script->hasScriptCounts)
|
||||||
updatePCCounts(PC, &codeStart, &countsUpdated);
|
updatePCCounts(PC, &countsUpdated);
|
||||||
target = next + GET_JUMP_OFFSET(next);
|
target = next + GET_JUMP_OFFSET(next);
|
||||||
fixDoubleTypes(target);
|
fixDoubleTypes(target);
|
||||||
}
|
}
|
||||||
|
@ -2631,7 +2638,7 @@ mjit::Compiler::generateMethod()
|
||||||
return status;
|
return status;
|
||||||
if (script->hasScriptCounts) {
|
if (script->hasScriptCounts) {
|
||||||
/* Code generated while inlining has been accounted for. */
|
/* Code generated while inlining has been accounted for. */
|
||||||
updatePCCounts(PC, &codeStart, &countsUpdated);
|
countsUpdated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2728,7 +2735,7 @@ mjit::Compiler::generateMethod()
|
||||||
* switch statements (could be fixed).
|
* switch statements (could be fixed).
|
||||||
*/
|
*/
|
||||||
if (script->hasScriptCounts)
|
if (script->hasScriptCounts)
|
||||||
updatePCCounts(PC, &codeStart, &countsUpdated);
|
updatePCCounts(PC, &countsUpdated);
|
||||||
#if defined JS_CPU_ARM /* Need to implement jump(BaseIndex) for ARM */
|
#if defined JS_CPU_ARM /* Need to implement jump(BaseIndex) for ARM */
|
||||||
frame.syncAndKillEverything();
|
frame.syncAndKillEverything();
|
||||||
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
||||||
|
@ -2748,7 +2755,7 @@ mjit::Compiler::generateMethod()
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_LOOKUPSWITCH)
|
BEGIN_CASE(JSOP_LOOKUPSWITCH)
|
||||||
if (script->hasScriptCounts)
|
if (script->hasScriptCounts)
|
||||||
updatePCCounts(PC, &codeStart, &countsUpdated);
|
updatePCCounts(PC, &countsUpdated);
|
||||||
frame.syncAndForgetEverything();
|
frame.syncAndForgetEverything();
|
||||||
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
||||||
|
|
||||||
|
@ -2792,7 +2799,7 @@ mjit::Compiler::generateMethod()
|
||||||
{
|
{
|
||||||
/* At the byte level, this is always fused with IFNE or IFNEX. */
|
/* At the byte level, this is always fused with IFNE or IFNEX. */
|
||||||
if (script->hasScriptCounts)
|
if (script->hasScriptCounts)
|
||||||
updatePCCounts(PC, &codeStart, &countsUpdated);
|
updatePCCounts(PC, &countsUpdated);
|
||||||
jsbytecode *target = &PC[JSOP_MOREITER_LENGTH];
|
jsbytecode *target = &PC[JSOP_MOREITER_LENGTH];
|
||||||
JSOp next = JSOp(*target);
|
JSOp next = JSOp(*target);
|
||||||
JS_ASSERT(next == JSOP_IFNE);
|
JS_ASSERT(next == JSOP_IFNE);
|
||||||
|
@ -3153,7 +3160,7 @@ mjit::Compiler::generateMethod()
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_STOP)
|
BEGIN_CASE(JSOP_STOP)
|
||||||
if (script->hasScriptCounts)
|
if (script->hasScriptCounts)
|
||||||
updatePCCounts(PC, &codeStart, &countsUpdated);
|
updatePCCounts(PC, &countsUpdated);
|
||||||
emitReturn(NULL);
|
emitReturn(NULL);
|
||||||
goto done;
|
goto done;
|
||||||
END_CASE(JSOP_STOP)
|
END_CASE(JSOP_STOP)
|
||||||
|
@ -3231,7 +3238,7 @@ mjit::Compiler::generateMethod()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script->hasScriptCounts) {
|
if (script->hasScriptCounts) {
|
||||||
size_t length = masm.size() - masm.distanceOf(codeStart);
|
size_t length = masm.size() - masm.distanceOf(inlineStart);
|
||||||
bool typesUpdated = false;
|
bool typesUpdated = false;
|
||||||
|
|
||||||
/* Update information about the type of value pushed by arithmetic ops. */
|
/* Update information about the type of value pushed by arithmetic ops. */
|
||||||
|
@ -3253,21 +3260,16 @@ mjit::Compiler::generateMethod()
|
||||||
typesUpdated = true;
|
typesUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (countsUpdated || typesUpdated || length != 0) {
|
if (!countsUpdated && (typesUpdated || length != 0))
|
||||||
if (!countsUpdated)
|
updatePCCounts(lastPC, &countsUpdated);
|
||||||
updatePCCounts(lastPC, &codeStart, &countsUpdated);
|
}
|
||||||
|
/* Update how much code we generated for this opcode */
|
||||||
if (pcLengths) {
|
if (pcLengths) {
|
||||||
/* Fill in the amount of inline code generated for the op. */
|
size_t length = masm.size() - masm.distanceOf(inlineStart);
|
||||||
uint32_t offset = ssa.frameLength(a->inlineIndex) + lastPC - script->code;
|
size_t stubLength = stubcc.size() - stubcc.masm.distanceOf(stubStart);
|
||||||
pcLengths[offset].codeLength += length;
|
uint32_t offset = ssa.frameLength(a->inlineIndex) + lastPC - script->code;
|
||||||
}
|
pcLengths[offset].inlineLength += length;
|
||||||
}
|
pcLengths[offset].stubLength += stubLength;
|
||||||
} else if (pcLengths) {
|
|
||||||
/* Fill in the amount of inline code generated for the op. */
|
|
||||||
size_t length = masm.size() - masm.distanceOf(codeStart);
|
|
||||||
uint32_t offset = ssa.frameLength(a->inlineIndex) + lastPC - script->code;
|
|
||||||
pcLengths[offset].codeLength += length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.assertValidRegisterState();
|
frame.assertValidRegisterState();
|
||||||
|
@ -3281,10 +3283,12 @@ mjit::Compiler::generateMethod()
|
||||||
#undef BEGIN_CASE
|
#undef BEGIN_CASE
|
||||||
|
|
||||||
void
|
void
|
||||||
mjit::Compiler::updatePCCounts(jsbytecode *pc, Label *start, bool *updated)
|
mjit::Compiler::updatePCCounts(jsbytecode *pc, bool *updated)
|
||||||
{
|
{
|
||||||
JS_ASSERT(script->hasScriptCounts);
|
JS_ASSERT(script->hasScriptCounts);
|
||||||
|
|
||||||
|
Label start = masm.label();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bump the METHODJIT count for the opcode, read the METHODJIT_CODE_LENGTH
|
* Bump the METHODJIT count for the opcode, read the METHODJIT_CODE_LENGTH
|
||||||
* and METHODJIT_PICS_LENGTH counts, indicating the amounts of inline path
|
* and METHODJIT_PICS_LENGTH counts, indicating the amounts of inline path
|
||||||
|
@ -3304,9 +3308,15 @@ mjit::Compiler::updatePCCounts(jsbytecode *pc, Label *start, bool *updated)
|
||||||
|
|
||||||
PCCounts counts = script->getPCCounts(pc);
|
PCCounts counts = script->getPCCounts(pc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The inlineLength represents the actual length of the opcode generated,
|
||||||
|
* but this includes the instrumentation as well as other possibly not
|
||||||
|
* useful bytes. This extra cruft is accumulated in codeLengthAugment and
|
||||||
|
* will be taken out accordingly.
|
||||||
|
*/
|
||||||
double *code = &counts.get(PCCounts::BASE_METHODJIT_CODE);
|
double *code = &counts.get(PCCounts::BASE_METHODJIT_CODE);
|
||||||
double *codeLength = &pcLengths[offset].codeLength;
|
masm.addCount(&pcLengths[offset].inlineLength, code, reg);
|
||||||
masm.addCount(codeLength, code, reg);
|
masm.addCount(&pcLengths[offset].codeLengthAugment, code, reg);
|
||||||
|
|
||||||
double *pics = &counts.get(PCCounts::BASE_METHODJIT_PICS);
|
double *pics = &counts.get(PCCounts::BASE_METHODJIT_PICS);
|
||||||
double *picsLength = &pcLengths[offset].picsLength;
|
double *picsLength = &pcLengths[offset].picsLength;
|
||||||
|
@ -3318,8 +3328,9 @@ mjit::Compiler::updatePCCounts(jsbytecode *pc, Label *start, bool *updated)
|
||||||
/* Reload the base register's original value. */
|
/* Reload the base register's original value. */
|
||||||
masm.loadPtr(frame.addressOfTop(), reg);
|
masm.loadPtr(frame.addressOfTop(), reg);
|
||||||
|
|
||||||
/* The start label should reflect the code for the op, not instrumentation. */
|
/* The count of code executed should not reflect instrumentation as well */
|
||||||
*start = masm.label();
|
pcLengths[offset].codeLengthAugment -= masm.size() - masm.distanceOf(start);
|
||||||
|
|
||||||
*updated = true;
|
*updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7089,7 +7100,7 @@ mjit::Compiler::jumpAndRun(Jump j, jsbytecode *target, Jump *slow, bool *trampol
|
||||||
*/
|
*/
|
||||||
uint32_t offset = ssa.frameLength(a->inlineIndex) + PC - script->code;
|
uint32_t offset = ssa.frameLength(a->inlineIndex) + PC - script->code;
|
||||||
size_t length = stubcc.masm.size() - stubcc.masm.distanceOf(start);
|
size_t length = stubcc.masm.size() - stubcc.masm.distanceOf(start);
|
||||||
pcLengths[offset].codeLength += length;
|
pcLengths[offset].codeLengthAugment += length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -528,7 +528,7 @@ private:
|
||||||
CompileStatus finishThisUp();
|
CompileStatus finishThisUp();
|
||||||
CompileStatus pushActiveFrame(JSScript *script, uint32_t argc);
|
CompileStatus pushActiveFrame(JSScript *script, uint32_t argc);
|
||||||
void popActiveFrame();
|
void popActiveFrame();
|
||||||
void updatePCCounts(jsbytecode *pc, Label *start, bool *updated);
|
void updatePCCounts(jsbytecode *pc, bool *updated);
|
||||||
void updatePCTypes(jsbytecode *pc, FrameEntry *fe);
|
void updatePCTypes(jsbytecode *pc, FrameEntry *fe);
|
||||||
void updateArithCounts(jsbytecode *pc, FrameEntry *fe,
|
void updateArithCounts(jsbytecode *pc, FrameEntry *fe,
|
||||||
JSValueType firstUseType, JSValueType secondUseType);
|
JSValueType firstUseType, JSValueType secondUseType);
|
||||||
|
|
|
@ -595,8 +595,13 @@ struct NativeMapEntry {
|
||||||
|
|
||||||
/* Per-op counts of performance metrics. */
|
/* Per-op counts of performance metrics. */
|
||||||
struct PCLengthEntry {
|
struct PCLengthEntry {
|
||||||
double codeLength; /* amount of inline code generated */
|
double inlineLength; /* amount of inline code generated */
|
||||||
double picsLength; /* amount of PIC stub code generated */
|
double picsLength; /* amount of PIC stub code generated */
|
||||||
|
double stubLength; /* amount of stubcc code generated */
|
||||||
|
double codeLengthAugment; /* augment to inlineLength to be added
|
||||||
|
at runtime, represents instrumentation
|
||||||
|
taken out or common stubcc accounted
|
||||||
|
for (instead of just adding inlineLength) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
#include "jsnum.h"
|
#include "jsnum.h"
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
|
|
||||||
|
#include "methodjit/MethodJIT.h"
|
||||||
|
#include "methodjit/Compiler.h"
|
||||||
|
|
||||||
#include "vm/SPSProfiler.h"
|
#include "vm/SPSProfiler.h"
|
||||||
#include "vm/StringBuffer.h"
|
#include "vm/StringBuffer.h"
|
||||||
|
|
||||||
|
@ -30,6 +33,12 @@ SPSProfiler::~SPSProfiler()
|
||||||
for (ProfileStringMap::Enum e(strings); !e.empty(); e.popFront())
|
for (ProfileStringMap::Enum e(strings); !e.empty(); e.popFront())
|
||||||
rt->array_delete(e.front().value);
|
rt->array_delete(e.front().value);
|
||||||
}
|
}
|
||||||
|
#ifdef JS_METHODJIT
|
||||||
|
if (jminfo.initialized()) {
|
||||||
|
for (JITInfoMap::Enum e(jminfo); !e.empty(); e.popFront())
|
||||||
|
rt->delete_(e.front().value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -196,6 +205,186 @@ SPSProfiler::allocProfileString(JSContext *cx, JSScript *script, JSFunction *may
|
||||||
return cstr;
|
return cstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef JS_METHODJIT
|
||||||
|
typedef SPSProfiler::JMChunkInfo JMChunkInfo;
|
||||||
|
|
||||||
|
JMChunkInfo::JMChunkInfo(mjit::JSActiveFrame *frame,
|
||||||
|
mjit::PCLengthEntry *pcLengths,
|
||||||
|
mjit::JITChunk *chunk)
|
||||||
|
: mainStart(frame->mainCodeStart),
|
||||||
|
mainEnd(frame->mainCodeEnd),
|
||||||
|
stubStart(frame->stubCodeStart),
|
||||||
|
stubEnd(frame->stubCodeEnd),
|
||||||
|
pcLengths(pcLengths),
|
||||||
|
chunk(chunk)
|
||||||
|
{}
|
||||||
|
|
||||||
|
jsbytecode*
|
||||||
|
SPSProfiler::ipToPC(JSScript *script, size_t ip)
|
||||||
|
{
|
||||||
|
JS_ASSERT(jminfo.initialized());
|
||||||
|
JITInfoMap::Ptr ptr = jminfo.lookup(script);
|
||||||
|
if (!ptr)
|
||||||
|
return NULL;
|
||||||
|
JMScriptInfo *info = ptr->value;
|
||||||
|
|
||||||
|
/* First check if this ip is in any of the ICs compiled for the script */
|
||||||
|
for (int i = 0; i < info->ics.length(); i++) {
|
||||||
|
ICInfo &ic = info->ics[i];
|
||||||
|
if (ic.base <= ip && ip < ic.base + ic.size)
|
||||||
|
return ic.pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise if it's not in any of the chunks, then we can't find it */
|
||||||
|
for (int i = 0; i < info->chunks.length(); i++) {
|
||||||
|
jsbytecode *pc = info->chunks[i].convert(script, ip);
|
||||||
|
if (pc != NULL)
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jsbytecode*
|
||||||
|
JMChunkInfo::convert(JSScript *script, size_t ip)
|
||||||
|
{
|
||||||
|
if (mainStart <= ip && ip < mainEnd) {
|
||||||
|
size_t offset = 0;
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < script->length - 1; i++) {
|
||||||
|
offset += (uint32_t) pcLengths[i].inlineLength;
|
||||||
|
if (mainStart + offset > ip)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return &script->code[i];
|
||||||
|
} else if (stubStart <= ip && ip < stubEnd) {
|
||||||
|
size_t offset = 0;
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < script->length - 1; i++) {
|
||||||
|
offset += (uint32_t) pcLengths[i].stubLength;
|
||||||
|
if (stubStart + offset > ip)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return &script->code[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SPSProfiler::registerMJITCode(mjit::JITChunk *chunk,
|
||||||
|
mjit::JSActiveFrame *outerFrame,
|
||||||
|
mjit::JSActiveFrame **inlineFrames)
|
||||||
|
{
|
||||||
|
if (!jminfo.initialized() && !jminfo.init(100))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
JS_ASSERT(chunk->pcLengths != NULL);
|
||||||
|
|
||||||
|
JMChunkInfo *info = registerScript(outerFrame, chunk->pcLengths, chunk);
|
||||||
|
if (!info)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The pcLengths array has entries for both the outerFrame's script and also
|
||||||
|
* all of the inlineFrames' scripts. The layout is something like:
|
||||||
|
*
|
||||||
|
* [ outerFrame info ] [ inline frame 1 ] [ inline frame 2 ] ...
|
||||||
|
*
|
||||||
|
* This local pcLengths pointer tracks the position of each inline frame's
|
||||||
|
* pcLengths array. Each section of the array has length script->length for
|
||||||
|
* the corresponding script for that frame.
|
||||||
|
*/
|
||||||
|
mjit::PCLengthEntry *pcLengths = chunk->pcLengths + outerFrame->script->length;
|
||||||
|
for (int i = 0; i < chunk->nInlineFrames; i++) {
|
||||||
|
JMChunkInfo *child = registerScript(inlineFrames[i], pcLengths, chunk);
|
||||||
|
if (!child)
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
* When JM tells us about new code, each inline ActiveFrame only has the
|
||||||
|
* start/end listed relative to the start of the main instruction
|
||||||
|
* streams. This is corrected here so the addresses listed on the
|
||||||
|
* JMChunkInfo structure are absolute and can be tested directly.
|
||||||
|
*/
|
||||||
|
child->mainStart += info->mainStart;
|
||||||
|
child->mainEnd += info->mainStart;
|
||||||
|
child->stubStart += info->stubStart;
|
||||||
|
child->stubEnd += info->stubStart;
|
||||||
|
|
||||||
|
pcLengths += inlineFrames[i]->script->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JMChunkInfo*
|
||||||
|
SPSProfiler::registerScript(mjit::JSActiveFrame *frame,
|
||||||
|
mjit::PCLengthEntry *entries,
|
||||||
|
mjit::JITChunk *chunk)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* An inlined script could possibly be compiled elsewhere as not having been
|
||||||
|
* inlined, so each JSScript* must be associated with a list of chunks
|
||||||
|
* instead of just one. Also, our script may already be in the map.
|
||||||
|
*/
|
||||||
|
JITInfoMap::AddPtr ptr = jminfo.lookupForAdd(frame->script);
|
||||||
|
JMScriptInfo *info;
|
||||||
|
if (ptr) {
|
||||||
|
info = ptr->value;
|
||||||
|
JS_ASSERT(info->chunks.length() > 0);
|
||||||
|
} else {
|
||||||
|
info = rt->new_<JMScriptInfo>();
|
||||||
|
if (info == NULL || !jminfo.add(ptr, frame->script, info))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!info->chunks.append(JMChunkInfo(frame, entries, chunk)))
|
||||||
|
return NULL;
|
||||||
|
return info->chunks.end() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SPSProfiler::registerICCode(mjit::JITChunk *chunk,
|
||||||
|
JSScript *script, jsbytecode *pc,
|
||||||
|
void *base, size_t size)
|
||||||
|
{
|
||||||
|
JS_ASSERT(jminfo.initialized());
|
||||||
|
JITInfoMap::Ptr ptr = jminfo.lookup(script);
|
||||||
|
JS_ASSERT(ptr);
|
||||||
|
return ptr->value->ics.append(ICInfo(base, size, pc));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SPSProfiler::discardMJITCode(mjit::JITScript *jscr,
|
||||||
|
mjit::JITChunk *chunk, void* address)
|
||||||
|
{
|
||||||
|
if (!jminfo.initialized())
|
||||||
|
return;
|
||||||
|
|
||||||
|
unregisterScript(jscr->script, chunk);
|
||||||
|
for (int i = 0; i < chunk->nInlineFrames; i++)
|
||||||
|
unregisterScript(chunk->inlineFrames()[i].fun->script(), chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SPSProfiler::unregisterScript(JSScript *script, mjit::JITChunk *chunk)
|
||||||
|
{
|
||||||
|
JITInfoMap::Ptr ptr = jminfo.lookup(script);
|
||||||
|
if (!ptr)
|
||||||
|
return;
|
||||||
|
JMScriptInfo *info = ptr->value;
|
||||||
|
for (int i = 0; i < info->chunks.length(); i++) {
|
||||||
|
if (info->chunks[i].chunk == chunk) {
|
||||||
|
info->chunks.erase(&info->chunks[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (info->chunks.length() == 0) {
|
||||||
|
jminfo.remove(ptr);
|
||||||
|
rt->delete_(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SPSEntryMarker::SPSEntryMarker(JSRuntime *rt JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
|
SPSEntryMarker::SPSEntryMarker(JSRuntime *rt JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
|
||||||
: profiler(&rt->spsProfiler)
|
: profiler(&rt->spsProfiler)
|
||||||
{
|
{
|
||||||
|
|
|
@ -107,6 +107,15 @@ namespace js {
|
||||||
|
|
||||||
class ProfileEntry;
|
class ProfileEntry;
|
||||||
|
|
||||||
|
#ifdef JS_METHODJIT
|
||||||
|
namespace mjit {
|
||||||
|
struct JITChunk;
|
||||||
|
struct JITScript;
|
||||||
|
struct JSActiveFrame;
|
||||||
|
struct PCLengthEntry;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef HashMap<JSScript*, const char*, DefaultHasher<JSScript*>, SystemAllocPolicy>
|
typedef HashMap<JSScript*, const char*, DefaultHasher<JSScript*>, SystemAllocPolicy>
|
||||||
ProfileStringMap;
|
ProfileStringMap;
|
||||||
|
|
||||||
|
@ -162,6 +171,78 @@ class SPSProfiler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef JS_METHODJIT
|
||||||
|
struct ICInfo
|
||||||
|
{
|
||||||
|
size_t base;
|
||||||
|
size_t size;
|
||||||
|
jsbytecode *pc;
|
||||||
|
|
||||||
|
ICInfo(void *base, size_t size, jsbytecode *pc)
|
||||||
|
: base(size_t(base)), size(size), pc(pc)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JMChunkInfo
|
||||||
|
{
|
||||||
|
size_t mainStart; // bounds for the inline code
|
||||||
|
size_t mainEnd;
|
||||||
|
size_t stubStart; // bounds of the ool code
|
||||||
|
size_t stubEnd;
|
||||||
|
mjit::PCLengthEntry *pcLengths; // pcLengths for this chunk
|
||||||
|
mjit::JITChunk *chunk; // stored to test when removing
|
||||||
|
|
||||||
|
JMChunkInfo(mjit::JSActiveFrame *frame,
|
||||||
|
mjit::PCLengthEntry *pcLengths,
|
||||||
|
mjit::JITChunk *chunk);
|
||||||
|
|
||||||
|
jsbytecode *convert(JSScript *script, size_t ip);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JMScriptInfo
|
||||||
|
{
|
||||||
|
Vector<ICInfo, 0, SystemAllocPolicy> ics;
|
||||||
|
Vector<JMChunkInfo, 1, SystemAllocPolicy> chunks;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef HashMap<JSScript*, JMScriptInfo*, DefaultHasher<JSScript*>,
|
||||||
|
SystemAllocPolicy> JITInfoMap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the mapping which facilitates translation from an ip to a
|
||||||
|
* jsbytecode*. The mapping is from a JSScript* to a set of chunks and ics
|
||||||
|
* which are associated with the script. This way lookup/translation doesn't
|
||||||
|
* have to do something like iterate the entire map.
|
||||||
|
*
|
||||||
|
* Each IC is easy to test because they all have only one pc associated with
|
||||||
|
* them, and the range is easy to check. The main chunks of code are a bit
|
||||||
|
* harder because there are both the inline and out of line streams which
|
||||||
|
* need to be tested. Each of these streams is described by the pcLengths
|
||||||
|
* array stored within each chunk. This array describes the width of each
|
||||||
|
* opcode of the corresponding JSScript, and has the same number of entries
|
||||||
|
* as script->length.
|
||||||
|
*/
|
||||||
|
JITInfoMap jminfo;
|
||||||
|
|
||||||
|
bool registerMJITCode(mjit::JITChunk *chunk,
|
||||||
|
mjit::JSActiveFrame *outerFrame,
|
||||||
|
mjit::JSActiveFrame **inlineFrames);
|
||||||
|
void discardMJITCode(mjit::JITScript *jscr,
|
||||||
|
mjit::JITChunk *chunk, void* address);
|
||||||
|
bool registerICCode(mjit::JITChunk *chunk, JSScript *script, jsbytecode* pc,
|
||||||
|
void *start, size_t size);
|
||||||
|
jsbytecode *ipToPC(JSScript *script, size_t ip);
|
||||||
|
|
||||||
|
private:
|
||||||
|
JMChunkInfo *registerScript(mjit::JSActiveFrame *frame,
|
||||||
|
mjit::PCLengthEntry *lenths,
|
||||||
|
mjit::JITChunk *chunk);
|
||||||
|
void unregisterScript(JSScript *script, mjit::JITChunk *chunk);
|
||||||
|
public:
|
||||||
|
#else
|
||||||
|
jsbytecode *ipToPC(JSScript *script, size_t ip) { return NULL; }
|
||||||
|
#endif
|
||||||
|
|
||||||
void setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max);
|
void setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max);
|
||||||
const char *profileString(JSContext *cx, JSScript *script, JSFunction *maybeFun);
|
const char *profileString(JSContext *cx, JSScript *script, JSFunction *maybeFun);
|
||||||
void onScriptFinalized(JSScript *script);
|
void onScriptFinalized(JSScript *script);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче