diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 3009774a7b0..602b5f398d5 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -100,6 +100,7 @@ namespace nanojit { class Fragment; class Fragmento; class LirBuffer; + extern "C++" { template class HashMap; } } class TraceRecorder; class VMAllocator; @@ -114,6 +115,12 @@ typedef Queue SlotList; #define FRAGMENT_TABLE_SIZE 512 struct VMFragment; +#ifdef __cplusplus +struct REHashKey; +struct REHashFn; +typedef nanojit::HashMap REHashMap; +#endif + #define MONITOR_N_GLOBAL_STATES 4 struct GlobalState { JSObject* globalObj; @@ -181,6 +188,7 @@ struct JSTraceMonitor { CLS(nanojit::Assembler) reAssembler; CLS(nanojit::LirBuffer) reLirBuf; CLS(nanojit::Fragmento) reFragmento; + CLS(REHashMap) reFragments; /* Keep a list of recorders we need to abort on cache flush. */ CLS(TraceRecorder) abortStack; diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 1e6421926e2..eab4513e6de 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -2006,41 +2006,32 @@ typedef JSTempVector LInsList; /* Dummy GC for nanojit placement new. */ static GC gc; -static void * -HashRegExp(uint16 flags, const jschar *s, size_t n) -{ - uint32 h; - - for (h = 0; n; s++, n--) - h = JS_ROTATE_LEFT32(h, 4) ^ *s; - return (void *)(h + flags); -} - -struct RESideExit : public SideExit { - size_t re_length; - uint16 re_flags; - jschar re_chars[1]; -}; - -/* Return the cached fragment for the given regexp, or NULL. */ +/* Return the cached fragment for the given regexp, or create one. */ static Fragment* -LookupNativeRegExp(JSContext* cx, void* hash, uint16 re_flags, +LookupNativeRegExp(JSContext* cx, uint16 re_flags, const jschar* re_chars, size_t re_length) { - Fragmento* fragmento = JS_TRACE_MONITOR(cx).reFragmento; - Fragment* fragment = fragmento->getLoop(hash); - while (fragment) { - if (fragment->lastIns) { - RESideExit *exit = (RESideExit*)fragment->lastIns->record()->exit; - if (exit->re_flags == re_flags && - exit->re_length == re_length && - !memcmp(exit->re_chars, re_chars, re_length * sizeof(jschar))) { - return fragment; - } - } - fragment = fragment->peer; + JSTraceMonitor *tm = &JS_TRACE_MONITOR(cx); + VMAllocator &alloc = *tm->reAllocator; + REHashMap &table = *tm->reFragments; + + REHashKey k(re_length, re_flags, re_chars); + Fragment *frag = table.get(k); + + if (!frag) { + frag = new (alloc) Fragment(0); + frag->lirbuf = tm->reLirBuf; + frag->root = frag; + /* + * Copy the re_chars portion of the hash key into the Allocator, so + * its lifecycle is disconnected from the lifecycle of the + * underlying regexp. + */ + k.re_chars = (const jschar*) new (alloc) jschar[re_length]; + memcpy((void*) k.re_chars, re_chars, re_length * sizeof(jschar)); + table.put(k, frag); } - return NULL; + return frag; } static JSBool @@ -3065,16 +3056,13 @@ class RegExpNativeCompiler { GuardRecord* insertGuard(const jschar* re_chars, size_t re_length) { LIns* skip = lirBufWriter->insSkip(sizeof(GuardRecord) + - sizeof(RESideExit) + + sizeof(SideExit) + (re_length-1) * sizeof(jschar)); GuardRecord* guard = (GuardRecord *) skip->payload(); memset(guard, 0, sizeof(*guard)); - RESideExit* exit = (RESideExit*)(guard+1); + SideExit* exit = (SideExit*)(guard+1); guard->exit = exit; guard->exit->target = fragment; - exit->re_flags = re->flags; - exit->re_length = re_length; - memcpy(exit->re_chars, re_chars, re_length * sizeof(jschar)); fragment->lastIns = lir->insGuard(LIR_loop, NULL, skip); return guard; } @@ -3163,9 +3151,9 @@ class RegExpNativeCompiler { fail: if (alloc.outOfMemory() || oom || js_OverfullFragmento(tm, fragmento)) { - fragmento->clearFrags(); tm->reCodeAlloc->sweep(); alloc.reset(); + tm->reFragments = new (alloc) REHashMap(alloc); #ifdef DEBUG fragmento->labels = new (alloc) LabelMap(alloc, &js_LogController); lirbuf->names = new (alloc) LirNameMap(alloc, fragmento->labels); @@ -3216,19 +3204,11 @@ typedef void *(FASTCALL *NativeRegExp)(REGlobalData*, const jschar *); static NativeRegExp GetNativeRegExp(JSContext* cx, JSRegExp* re) { - Fragment *fragment; const jschar *re_chars; size_t re_length; - Fragmento* fragmento = JS_TRACE_MONITOR(cx).reFragmento; - re->source->getCharsAndLength(re_chars, re_length); - void* hash = HashRegExp(re->flags, re_chars, re_length); - fragment = LookupNativeRegExp(cx, hash, re->flags, re_chars, re_length); - if (!fragment) { - fragment = fragmento->getAnchor(hash); - fragment->lirbuf = JS_TRACE_MONITOR(cx).reLirBuf; - fragment->root = fragment; - } + Fragment *fragment = LookupNativeRegExp(cx, re->flags, re_chars, re_length); + JS_ASSERT(fragment); if (!fragment->code()) { if (!CompileRegExpToNative(cx, re, fragment)) return NULL; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 5d83a778322..c8d12451214 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -865,7 +865,7 @@ getLoop(JSTraceMonitor* tm, const void *ip, JSObject* globalObj, uint32 globalSh static Fragment* getAnchor(JSTraceMonitor* tm, const void *ip, JSObject* globalObj, uint32 globalShape, uint32 argc) { - VMFragment *f = new (&gc) VMFragment(ip, globalObj, globalShape, argc); + VMFragment *f = new VMFragment(ip, globalObj, globalShape, argc); JS_ASSERT(f); Fragment *p = getVMFragment(tm, ip, globalObj, globalShape, argc); @@ -6587,6 +6587,7 @@ js_InitJIT(JSTraceMonitor *tm) &js_LogController); if (!tm->reFragmento) { + tm->reFragments = new (reAlloc) REHashMap(reAlloc); Fragmento* fragmento = new (&gc) Fragmento(core, &js_LogController, 32, tm->reCodeAlloc); verbose_only(fragmento->labels = new (reAlloc) LabelMap(reAlloc, &js_LogController);) tm->reFragmento = fragmento; diff --git a/js/src/jstracer.h b/js/src/jstracer.h index fd88e871249..2ecda891b8f 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -411,7 +411,7 @@ struct VMSideExit : public nanojit::SideExit } }; -struct VMAllocator : public nanojit::Allocator +class VMAllocator : public nanojit::Allocator { public: @@ -438,6 +438,36 @@ public: uintptr_t mReserve[0x10000]; }; + +struct REHashKey { + size_t re_length; + uint16 re_flags; + const jschar* re_chars; + + REHashKey(size_t re_length, uint16 re_flags, const jschar *re_chars) + : re_length(re_length) + , re_flags(re_flags) + , re_chars(re_chars) + {} + + bool operator==(const REHashKey& other) const + { + return ((this->re_length == other.re_length) && + (this->re_flags == other.re_flags) && + !memcmp(this->re_chars, other.re_chars, + this->re_length * sizeof(jschar))); + } +}; + +struct REHashFn { + static size_t hash(const REHashKey& k) { + return + k.re_length + + k.re_flags + + nanojit::murmurhash(k.re_chars, k.re_length * sizeof(jschar)); + } +}; + struct FrameInfo { JSObject* callee; // callee function object JSObject* block; // caller block chain head diff --git a/js/src/nanojit/Fragmento.cpp b/js/src/nanojit/Fragmento.cpp index 3c3a4674bd2..09317b4ef18 100644 --- a/js/src/nanojit/Fragmento.cpp +++ b/js/src/nanojit/Fragmento.cpp @@ -250,7 +250,7 @@ namespace nanojit Fragment *Fragmento::newFrag(const void* ip) { GC *gc = _core->gc; - Fragment *f = NJ_NEW(gc, Fragment)(ip); + Fragment *f = new Fragment(ip); f->blacklistLevel = 5; return f; } diff --git a/js/src/nanojit/Fragmento.h b/js/src/nanojit/Fragmento.h index 5f6ac89c6a6..cb1f72d337c 100644 --- a/js/src/nanojit/Fragmento.h +++ b/js/src/nanojit/Fragmento.h @@ -128,7 +128,7 @@ namespace nanojit * It may turn out that that this arrangement causes too much traffic * between d and i-caches and that we need to carve up the structure differently. */ - class Fragment : public avmplus::GCFinalizedObject + class Fragment { public: Fragment(const void*);