Internalize and memoize FrameInfo structures (bug 501398, r=brendan).

This commit is contained in:
David Anderson 2009-09-29 14:33:43 -07:00
parent 0eaf0df2ca
commit a64d9ec66a
3 changed files with 106 additions and 9 deletions

View File

@ -126,6 +126,7 @@ struct VMFragment;
#ifdef __cplusplus
struct REHashKey;
struct REHashFn;
class FrameInfoCache;
typedef nanojit::HashMap<REHashKey, nanojit::Fragment*, REHashFn> REHashMap;
#endif
@ -177,6 +178,7 @@ struct JSTraceMonitor {
CLS(nanojit::Assembler) assembler;
CLS(nanojit::LirBuffer) lirbuf;
CLS(nanojit::LirBuffer) reLirBuf;
CLS(FrameInfoCache) frameCache;
#ifdef DEBUG
CLS(nanojit::LabelMap) labels;
#endif

View File

@ -1142,6 +1142,92 @@ IsSlotUndemotable(JSContext* cx, TreeInfo* ti, unsigned slot)
return oracle.isGlobalSlotUndemotable(cx, gslots[slot - ti->nStackTypes]);
}
class FrameInfoCache
{
struct Entry : public JSDHashEntryHdr
{
FrameInfo *fi;
};
static JSBool
MatchFrameInfo(JSDHashTable *table, const JSDHashEntryHdr *entry, const void *key) {
const FrameInfo* fi1 = ((const Entry*)entry)->fi;
const FrameInfo* fi2 = (const FrameInfo*)key;
if (memcmp(fi1, fi2, sizeof(FrameInfo)) != 0)
return JS_FALSE;
return memcmp(fi1->get_typemap(), fi2->get_typemap(),
fi1->callerHeight * sizeof(JSTraceType)) == 0;
}
static JSDHashNumber
HashFrameInfo(JSDHashTable *table, const void *key) {
FrameInfo* fi = (FrameInfo*)key;
size_t len = sizeof(FrameInfo) + fi->callerHeight * sizeof(JSTraceType);
JSDHashNumber h = 0;
const unsigned char *s = (const unsigned char*)fi;
for (size_t i = 0; i < len; i++, s++)
h = JS_ROTATE_LEFT32(h, 4) ^ *s;
return h;
}
static const JSDHashTableOps FrameCacheOps;
JSDHashTable *table;
public:
FrameInfoCache() {
init();
}
~FrameInfoCache() {
clear();
}
void clear() {
if (table) {
JS_DHashTableDestroy(table);
table = NULL;
}
}
bool reset() {
clear();
return init();
}
bool init() {
table = JS_NewDHashTable(&FrameCacheOps, NULL, sizeof(Entry),
JS_DHASH_DEFAULT_CAPACITY(32));
return table != NULL;
}
FrameInfo *memoize(const FrameInfo *fi, VMAllocator *allocator) {
Entry *entry = (Entry*)JS_DHashTableOperate(table, fi, JS_DHASH_ADD);
if (!entry)
return NULL;
if (!entry->fi) {
FrameInfo* n = (FrameInfo*)
allocator->alloc(sizeof(FrameInfo) + fi->callerHeight * sizeof(JSTraceType));
memcpy(n, fi, sizeof(FrameInfo) + fi->callerHeight * sizeof(JSTraceType));
entry->fi = n;
}
return entry->fi;
}
};
const JSDHashTableOps FrameInfoCache::FrameCacheOps =
{
JS_DHashAllocTable,
JS_DHashFreeTable,
FrameInfoCache::HashFrameInfo,
FrameInfoCache::MatchFrameInfo,
JS_DHashMoveEntryStub,
JS_DHashClearEntryStub,
JS_DHashFinalizeStub,
NULL
};
struct PCHashEntry : public JSDHashEntryStub {
size_t count;
};
@ -2562,6 +2648,7 @@ JSTraceMonitor::flush()
js_FragProfiling_FragFinalizer(f->head, this);
)
frameCache->reset();
dataAlloc->reset();
traceAlloc->reset();
codeAlloc->reset();
@ -2813,12 +2900,12 @@ public:
class FlushNativeStackFrameVisitor : public SlotVisitorBase
{
JSContext *mCx;
JSTraceType *mTypeMap;
const JSTraceType *mTypeMap;
double *mStack;
jsval *mStop;
public:
FlushNativeStackFrameVisitor(JSContext *cx,
JSTraceType *typeMap,
const JSTraceType *typeMap,
double *stack,
jsval *stop) :
mCx(cx),
@ -2827,7 +2914,7 @@ public:
mStop(stop)
{}
JSTraceType* getTypeMap()
const JSTraceType* getTypeMap()
{
return mTypeMap;
}
@ -3117,7 +3204,7 @@ GetClosureVar(JSContext* cx, JSObject* callee, const ClosureVarInfo* cv, double*
* @return the number of things we popped off of np.
*/
static JS_REQUIRES_STACK int
FlushNativeStackFrame(JSContext* cx, unsigned callDepth, JSTraceType* mp, double* np,
FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const JSTraceType* mp, double* np,
JSStackFrame* stopFrame)
{
jsval* stopAt = stopFrame ? &stopFrame->argv[-2] : NULL;
@ -6313,7 +6400,7 @@ LeaveTree(InterpState& state, VMSideExit* lr)
* type map pointer on the native call stack.
*/
SynthesizeFrame(cx, *fi, callee);
int slots = FlushNativeStackFrame(cx, 1 /* callDepth */, (JSTraceType*)(fi + 1),
int slots = FlushNativeStackFrame(cx, 1 /* callDepth */, (*callstack)->get_typemap(),
stack, cx->fp);
#ifdef DEBUG
JSStackFrame* fp = cx->fp;
@ -7176,6 +7263,7 @@ js_InitJIT(JSTraceMonitor *tm)
tm->tempAlloc = new VMAllocator();
tm->reTempAlloc = new VMAllocator();
tm->codeAlloc = new CodeAlloc();
tm->frameCache = new FrameInfoCache();
tm->flush();
verbose_only( tm->branches = NULL; )
@ -7283,6 +7371,11 @@ js_FinishJIT(JSTraceMonitor *tm)
delete[] tm->reservedDoublePool;
tm->reservedDoublePool = tm->reservedDoublePoolPtr = NULL;
if (tm->frameCache) {
delete tm->frameCache;
tm->frameCache = NULL;
}
if (tm->codeAlloc) {
delete tm->codeAlloc;
tm->codeAlloc = NULL;
@ -11503,9 +11596,8 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
if (sizeof(FrameInfo) + stackSlots * sizeof(JSTraceType) > LirBuffer::MAX_SKIP_PAYLOAD_SZB)
RETURN_STOP("interpreted function call requires saving too much stack");
FrameInfo* fi = (FrameInfo*)
traceMonitor->traceAlloc->alloc(sizeof(FrameInfo) +
stackSlots * sizeof(JSTraceType));
JSTraceType* typemap = reinterpret_cast<JSTraceType *>(fi + 1);
traceMonitor->tempAlloc->alloc(sizeof(FrameInfo) + stackSlots * sizeof(JSTraceType));
JSTraceType* typemap = (JSTraceType*)(fi + 1);
DetermineTypesVisitor detVisitor(*this, typemap);
VisitStackSlots(detVisitor, cx, 0);
@ -11527,6 +11619,9 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
if (callDepth >= treeInfo->maxCallDepth)
treeInfo->maxCallDepth = callDepth + 1;
fi = traceMonitor->frameCache->memoize(fi, traceMonitor->traceAlloc);
if (!fi)
RETURN_STOP("out of memory");
lir->insStorei(INS_CONSTPTR(fi), lirbuf->rp, callDepth * sizeof(FrameInfo*));
atoms = fun->u.i.script->atomMap.vector;

View File

@ -573,7 +573,7 @@ struct FrameInfo {
bool is_constructing() const { return (argc & CONSTRUCTING_FLAG) != 0; }
// The typemap just before the callee is called.
JSTraceType* get_typemap() { return (JSTraceType*) (this+1); }
const JSTraceType* get_typemap() const { return (JSTraceType*) (this+1); }
};
struct UnstableExit