From a51f22dbdfa94b919fd109528761cda6b964331c Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Wed, 22 Apr 2009 16:52:59 -0700 Subject: [PATCH] Need an API exposed to control code cache size (474497, r=bent,brendan, sr=mrbkap). --- dom/src/threads/nsDOMThreadService.cpp | 1 + js/src/jsapi.cpp | 14 +++++++ js/src/jsapi.h | 11 +++++- js/src/jscntxt.h | 6 +++ js/src/jsregexp.cpp | 5 +-- js/src/jstracer.cpp | 53 ++++++++++++++++++++------ js/src/jstracer.h | 5 ++- js/src/shell/js.cpp | 2 + js/src/xpconnect/src/xpcjsruntime.cpp | 1 + 9 files changed, 80 insertions(+), 18 deletions(-) diff --git a/dom/src/threads/nsDOMThreadService.cpp b/dom/src/threads/nsDOMThreadService.cpp index d01e35321aa..bd486fa9b31 100644 --- a/dom/src/threads/nsDOMThreadService.cpp +++ b/dom/src/threads/nsDOMThreadService.cpp @@ -1000,6 +1000,7 @@ nsDOMThreadService::CreateJSContext() JS_SetScriptStackQuota(cx, 100*1024*1024); JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT | JSOPTION_ANONFUNFIX); + JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 1 * 1024 * 1024); return cx.forget(); } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f25959b5b7b..54bda03fa60 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2600,6 +2600,20 @@ JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key) } } +JS_PUBLIC_API(void) +JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value) +{ + JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES); + js_SetMaxCodeCacheBytes(cx, value); +} + +JS_PUBLIC_API(uint32) +JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key) +{ + JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES); + return JS_THREAD_DATA(cx)->traceMonitor.maxCodeCacheBytes; +} + JS_PUBLIC_API(intN) JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index f8325088f4e..f297840c3ba 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1207,7 +1207,10 @@ typedef enum JSGCParamKey { JSGC_BYTES = 4, /* Number of times when GC was invoked. */ - JSGC_NUMBER = 5 + JSGC_NUMBER = 5, + + /* Max size of the code cache in bytes. */ + JSGC_MAX_CODE_CACHE_BYTES = 6 } JSGCParamKey; extern JS_PUBLIC_API(void) @@ -1216,6 +1219,12 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value); extern JS_PUBLIC_API(uint32) JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key); +extern JS_PUBLIC_API(void) +JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value); + +extern JS_PUBLIC_API(uint32) +JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key); + /* * Add a finalizer for external strings created by JS_NewExternalString (see * below) using a type-code returned from this function, and that understands diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 03cea70257c..b806b7391ad 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -153,6 +153,12 @@ struct JSTraceMonitor { uintN prohibitFlush; JSPackedBool needFlush; + /* + * Maximum size of the code cache before we start flushing. 1/16 of this + * size is used as threshold for the regular expression code cache. + */ + uint32 maxCodeCacheBytes; + /* * reservedObjects is a linked list (via fslots[0]) of preallocated JSObjects. * The JIT uses this to ensure that leaving a trace tree can't fail. diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 991281eb33d..362ef7b0388 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -71,9 +71,6 @@ #include "jstracer.h" using namespace avmplus; using namespace nanojit; - -/* Amount of memory in the RE fragmento before flushing. */ -#define MAX_MEM_IN_RE_FRAGMENTO (1 << 20) #endif typedef enum REOp { @@ -2442,7 +2439,7 @@ class RegExpNativeCompiler { return JS_TRUE; fail: if (lirbuf->outOMem() || oom || - js_OverfullFragmento(fragmento, MAX_MEM_IN_RE_FRAGMENTO)) { + js_OverfullFragmento(&JS_TRACE_MONITOR(cx), fragmento)) { fragmento->clearFrags(); lirbuf->rewind(); } else { diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 9f2b8f492e1..6ff7e415e6e 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -135,9 +135,6 @@ static const char tagChar[] = "OIDISIBI"; (MAX_NATIVE_STACK_SLOTS * sizeof(jsval) + \ MAX_CALL_STACK_ENTRIES * sizeof(JSInlineFrame)) -/* Amount of memory in the main fragmento before flushing. */ -#define MAX_MEM_IN_MAIN_FRAGMENTO (1 << 24) - /* Max number of branches per tree. */ #define MAX_BRANCHES 32 @@ -3212,8 +3209,8 @@ js_DeleteRecorder(JSContext* cx) /* * If we ran out of memory, flush the code cache. */ - if (JS_TRACE_MONITOR(cx).fragmento->assm()->error() == OutOMem - || js_OverfullFragmento(tm->fragmento, MAX_MEM_IN_MAIN_FRAGMENTO)) { + if (JS_TRACE_MONITOR(cx).fragmento->assm()->error() == OutOMem || + js_OverfullFragmento(tm, tm->fragmento)) { FlushJITCache(cx); return false; } @@ -3534,8 +3531,7 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer, f->root = f; f->lirbuf = tm->lirbuf; - if (f->lirbuf->outOMem() || - js_OverfullFragmento(tm->fragmento, MAX_MEM_IN_MAIN_FRAGMENTO)) { + if (f->lirbuf->outOMem() || js_OverfullFragmento(tm, tm->fragmento)) { FlushJITCache(cx); debug_only_v(printf("Out of memory recording new tree, flushing cache.\n");) return false; @@ -4594,9 +4590,8 @@ TraceRecorder::monitorRecording(JSContext* cx, TraceRecorder* tr, JSOp op) return JSMRS_STOP; } - if (tr->lirbuf->outOMem() || - js_OverfullFragmento(JS_TRACE_MONITOR(cx).fragmento, - MAX_MEM_IN_MAIN_FRAGMENTO)) { + if (tr->lirbuf->outOMem() || + js_OverfullFragmento(&JS_TRACE_MONITOR(cx), JS_TRACE_MONITOR(cx).fragmento)) { js_AbortRecording(cx, "no more LIR memory"); FlushJITCache(cx); return JSMRS_STOP; @@ -4837,6 +4832,22 @@ js_arm_check_vfp() { return false; } #endif /* NANOJIT_ARM */ +#define K *1024 +#define M K K +#define G K M + +void +js_SetMaxCodeCacheBytes(JSContext* cx, uint32 bytes) +{ + JSTraceMonitor* tm = &JS_THREAD_DATA(cx)->traceMonitor; + JS_ASSERT(tm->fragmento && tm->reFragmento); + if (bytes > 1 G) + bytes = 1 G; + if (bytes < 128 K) + bytes = 128 K; + tm->maxCodeCacheBytes = bytes; +} + void js_InitJIT(JSTraceMonitor *tm) { @@ -4853,6 +4864,11 @@ js_InitJIT(JSTraceMonitor *tm) did_we_check_processor_features = true; } + /* + * Set the default size for the code cache to 16MB. + */ + tm->maxCodeCacheBytes = 16 M; + if (!tm->fragmento) { JS_ASSERT(!tm->reservedDoublePool); Fragmento* fragmento = new (&gc) Fragmento(core, 32); @@ -4987,7 +5003,7 @@ js_PurgeScriptFragments(JSContext* cx, JSScript* script) } bool -js_OverfullFragmento(Fragmento *frago, size_t maxsz) +js_OverfullFragmento(JSTraceMonitor* tm, Fragmento *fragmento) { /* * You might imagine the outOMem flag on the lirbuf is sufficient @@ -5023,7 +5039,20 @@ js_OverfullFragmento(Fragmento *frago, size_t maxsz) * handled by the (few) callers of this function. * */ - return (frago->_stats.pages > (maxsz >> NJ_LOG2_PAGE_SIZE)); + jsuint maxsz = tm->maxCodeCacheBytes; + if (fragmento == tm->fragmento) { + if (tm->prohibitFlush) + return false; + } else { + /* + * At the time of making the code cache size configurable, we were using + * 16 MB for the main code cache and 1 MB for the regular expression code + * cache. We will stick to this 16:1 ratio here until we unify the two + * code caches. + */ + maxsz /= 16; + } + return (fragmento->_stats.pages > (maxsz >> NJ_LOG2_PAGE_SIZE)); } JS_FORCES_STACK JS_FRIEND_API(void) diff --git a/js/src/jstracer.h b/js/src/jstracer.h index cc6a6882354..bfa6d0550ec 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -679,7 +679,7 @@ extern void js_PurgeScriptFragments(JSContext* cx, JSScript* script); extern bool -js_OverfullFragmento(nanojit::Fragmento *frago, size_t maxsz); +js_OverfullFragmento(JSTraceMonitor* tm, nanojit::Fragmento *frago); extern void js_PurgeJITOracle(); @@ -687,6 +687,9 @@ js_PurgeJITOracle(); extern JSObject * js_GetBuiltinFunction(JSContext *cx, uintN index); +extern void +js_SetMaxCodeCacheBytes(JSContext* cx, uint32 bytes); + #else /* !JS_TRACER */ #define TRACE_0(x) ((void)0) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 943a60f5e35..8a384adeaf2 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4633,6 +4633,8 @@ main(int argc, char **argv, char **envp) if (!cx) return 1; + JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 16 * 1024 * 1024); + JS_BeginRequest(cx); glob = JS_NewObject(cx, &global_class, NULL, NULL); diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index dbbec0d0a86..14468363c71 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -1142,6 +1142,7 @@ XPCJSRuntime::OnJSContextNew(JSContext *cx) JSBool ok = JS_TRUE; if(!mStrIDs[0]) { + JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 16 * 1024 * 1024); JSAutoRequest ar(cx); for(uintN i = 0; i < IDX_TOTAL_COUNT; i++) {