Bug 710032 - CollectNativeRegions() utility to simplify handling of inlined frames. r=bhackett

--HG--
extra : rebase_source : 310d2cc0b58bad53d07e09924ae4d37762542457
This commit is contained in:
Steve Fink 2011-10-21 15:43:55 -07:00
parent 3d50ba406c
commit dc03ae210d
4 changed files with 170 additions and 30 deletions

View File

@ -55,6 +55,10 @@
#include "jsscript.h"
#include "jsstr.h"
#ifdef JS_METHODJIT
# include "methodjit/Compiler.h"
#endif
#include "jsobjinlines.h"
#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
@ -114,16 +118,115 @@ Probes::JITGranularityRequested()
return want;
}
/*
* 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
Probes::JITWatcher::CollectNativeRegions(RegionVector &regions,
JSRuntime *rt,
mjit::JITScript *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;
}
#ifdef JS_METHODJIT
void
Probes::registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr,
JSScript *script, JSFunction *fun,
js::mjit::Compiler_ActiveFrame **inlineFrames,
js::mjit::JSActiveFrame *outerFrame,
js::mjit::JSActiveFrame **inlineFrames,
void *mainCodeAddress, size_t mainCodeSize,
void *stubCodeAddress, size_t stubCodeSize)
{
for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p)
(*p)->registerMJITCode(cx, jscr, script, fun,
(*p)->registerMJITCode(cx, jscr, outerFrame,
inlineFrames,
mainCodeAddress, mainCodeSize,
stubCodeAddress, stubCodeSize);

View File

@ -52,7 +52,7 @@ namespace js {
namespace mjit {
struct NativeAddressInfo;
struct Compiler_ActiveFrame;
struct JSActiveFrame;
}
namespace Probes {
@ -230,12 +230,31 @@ enum JITReportGranularity {
*/
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;
static bool CollectNativeRegions(RegionVector &regions,
JSRuntime *rt,
mjit::JITScript *jit,
mjit::JSActiveFrame *outerFrame,
mjit::JSActiveFrame **inlineFrames);
virtual JITReportGranularity granularityRequested() = 0;
#ifdef JS_METHODJIT
virtual void registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr,
JSScript *script, JSFunction *fun,
mjit::Compiler_ActiveFrame** inlineFrames,
mjit::JSActiveFrame *outerFrame,
mjit::JSActiveFrame **inlineFrames,
void *mainCodeAddress, size_t mainCodeSize,
void *stubCodeAddress, size_t stubCodeSize) = 0;
@ -282,8 +301,8 @@ JITGranularityRequested();
*/
void
registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr,
JSScript *script, JSFunction *fun,
mjit::Compiler_ActiveFrame** inlineFrames,
mjit::JSActiveFrame *outerFrame,
mjit::JSActiveFrame **inlineFrames,
void *mainCodeAddress, size_t mainCodeSize,
void *stubCodeAddress, size_t stubCodeSize);

View File

@ -486,8 +486,10 @@ void
mjit::Compiler::popActiveFrame()
{
JS_ASSERT(a->parent);
a->mainCodeEnd = masm.size();
a->stubCodeEnd = stubcc.size();
this->PC = a->parentPC;
this->a = a->parent;
this->a = (ActiveFrame *) a->parent;
this->script = a->script;
this->analysis = this->script->analysis();
@ -551,9 +553,14 @@ mjit::Compiler::performCompilation(JITScript **jitp)
#undef CHECK_STATUS
mjit::JSActiveFrame::JSActiveFrame()
: parent(NULL), parentPC(NULL), script(NULL), inlineIndex(UINT32_MAX)
{
}
mjit::Compiler::ActiveFrame::ActiveFrame(JSContext *cx)
: parent(NULL), parentPC(NULL), script(NULL), jumpMap(NULL),
inlineIndex(UINT32_MAX), varTypes(NULL), needReturnValue(false),
: jumpMap(NULL),
varTypes(NULL), needReturnValue(false),
syncReturnValue(false), returnValueDouble(false), returnSet(false),
returnEntry(NULL), returnJumps(NULL), exitState(NULL)
{}
@ -922,6 +929,9 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
return Compile_Abort;
}
a->mainCodeEnd = masm.size();
a->stubCodeEnd = stubcc.size();
for (size_t i = 0; i < branchPatches.length(); i++) {
Label label = labelOf(branchPatches[i].pc, branchPatches[i].inlineIndex);
branchPatches[i].jump.linkTo(label, &masm);
@ -1385,8 +1395,9 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
JSC::ExecutableAllocator::makeExecutable(result, masm.size() + stubcc.size());
JSC::ExecutableAllocator::cacheFlush(result, masm.size() + stubcc.size());
Probes::registerMJITCode(cx, jit, script, script->function() ? script->function() : NULL,
(mjit::Compiler_ActiveFrame**) inlineFrames.begin(),
Probes::registerMJITCode(cx, jit,
a,
(JSActiveFrame**) inlineFrames.begin(),
result, masm.size(),
result + masm.size(), stubcc.size());

View File

@ -62,6 +62,27 @@ struct InvariantCodePatch {
InvariantCodePatch() : hasPatch(false) {}
};
struct JSActiveFrame {
JSActiveFrame *parent;
jsbytecode *parentPC;
JSScript *script;
/*
* Index into inlineFrames or OUTER_FRAME, matches this frame's index in
* the cross script SSA.
*/
uint32_t inlineIndex;
/* JIT code generation tracking state */
size_t mainCodeStart;
size_t stubCodeStart;
size_t mainCodeEnd;
size_t stubCodeEnd;
size_t inlinePCOffset;
JSActiveFrame();
};
class Compiler : public BaseCompiler
{
friend class StubCompiler;
@ -355,26 +376,12 @@ class Compiler : public BaseCompiler
*/
public:
struct ActiveFrame {
ActiveFrame *parent;
jsbytecode *parentPC;
JSScript *script;
struct ActiveFrame : public JSActiveFrame {
Label *jumpMap;
/*
* Index into inlineFrames or OUTER_FRAME, matches this frame's index
* in the cross script SSA.
*/
uint32_t inlineIndex;
/* Current types for non-escaping vars in the script. */
VarType *varTypes;
/* JIT code generation tracking state */
size_t mainCodeStart;
size_t stubCodeStart;
size_t inlinePCOffset;
/* State for managing return from inlined frames. */
bool needReturnValue; /* Return value will be used. */
bool syncReturnValue; /* Return value should be fully synced. */
@ -470,7 +477,7 @@ private:
return PC;
ActiveFrame *scan = a;
while (scan && scan->parent != outer)
scan = scan->parent;
scan = static_cast<ActiveFrame *>(scan->parent);
return scan->parentPC;
}
@ -491,7 +498,7 @@ private:
while (na->parent) {
if (na->exitState)
return true;
na = na->parent;
na = static_cast<ActiveFrame *>(na->parent);
}
return false;
}