diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 70ae1ccc0d09..80cf29f8a84e 100755 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -126,6 +126,7 @@ struct VMFragment; #ifdef __cplusplus struct REHashKey; struct REHashFn; +class FrameInfoCache; typedef nanojit::HashMap 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 diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index af8c5b62ff5f..8ff252b55e6e 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1142,6 +1142,94 @@ 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; + VMAllocator *allocator; + + public: + FrameInfoCache(VMAllocator *allocator) : allocator(allocator) { + 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) { + 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; }; @@ -2566,6 +2654,7 @@ JSTraceMonitor::flush() js_FragProfiling_FragFinalizer(f->head, this); ) + frameCache->reset(); dataAlloc->reset(); traceAlloc->reset(); codeAlloc->reset(); @@ -2817,12 +2906,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), @@ -2831,7 +2920,7 @@ public: mStop(stop) {} - JSTraceType* getTypeMap() + const JSTraceType* getTypeMap() { return mTypeMap; } @@ -3121,7 +3210,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; @@ -6301,7 +6390,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; @@ -7164,6 +7253,7 @@ js_InitJIT(JSTraceMonitor *tm) tm->tempAlloc = new VMAllocator(); tm->reTempAlloc = new VMAllocator(); tm->codeAlloc = new CodeAlloc(); + tm->frameCache = new FrameInfoCache(tm->dataAlloc); tm->flush(); verbose_only( tm->branches = NULL; ) @@ -7271,6 +7361,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; @@ -11614,9 +11709,8 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, // Generate a type map for the outgoing frame and stash it in the LIR unsigned stackSlots = NativeStackSlots(cx, 0 /* callDepth */); FrameInfo* fi = (FrameInfo*) - traceMonitor->traceAlloc->alloc(sizeof(FrameInfo) + - stackSlots * sizeof(JSTraceType)); - JSTraceType* typemap = reinterpret_cast(fi + 1); + traceMonitor->tempAlloc->alloc(sizeof(FrameInfo) + stackSlots * sizeof(JSTraceType)); + JSTraceType* typemap = (JSTraceType*)(fi + 1); DetermineTypesVisitor detVisitor(*this, typemap); VisitStackSlots(detVisitor, cx, 0); @@ -11638,6 +11732,9 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, if (callDepth >= treeInfo->maxCallDepth) treeInfo->maxCallDepth = callDepth + 1; + fi = traceMonitor->frameCache->memoize(fi); + if (!fi) + RETURN_STOP("out of memory"); lir->insStorei(INS_CONSTPTR(fi), lirbuf->rp, callDepth * sizeof(FrameInfo*)); atoms = fun->u.i.script->atomMap.vector; diff --git a/js/src/jstracer.h b/js/src/jstracer.h index fac1fdffb12a..f8b1cdbc50bd 100755 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -574,7 +574,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