mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 631951 - Shrink methodjit memory usage by interpreting a few times before compiling (r=dvander)
This commit is contained in:
parent
f174853c0f
commit
42e73fa7bc
@ -354,6 +354,7 @@ user_pref("browser.EULA.override", true);
|
|||||||
user_pref("javascript.options.tracejit.content", true);
|
user_pref("javascript.options.tracejit.content", true);
|
||||||
user_pref("javascript.options.methodjit.content", true);
|
user_pref("javascript.options.methodjit.content", true);
|
||||||
user_pref("javascript.options.jitprofiling.content", true);
|
user_pref("javascript.options.jitprofiling.content", true);
|
||||||
|
user_pref("javascript.options.methodjit_always", false);
|
||||||
user_pref("gfx.color_management.force_srgb", true);
|
user_pref("gfx.color_management.force_srgb", true);
|
||||||
user_pref("network.manage-offline-status", false);
|
user_pref("network.manage-offline-status", false);
|
||||||
user_pref("test.mousescroll", true);
|
user_pref("test.mousescroll", true);
|
||||||
|
@ -1019,6 +1019,7 @@ static const char js_methodjit_content_str[] = JS_OPTIONS_DOT_STR "methodjit.c
|
|||||||
static const char js_methodjit_chrome_str[] = JS_OPTIONS_DOT_STR "methodjit.chrome";
|
static const char js_methodjit_chrome_str[] = JS_OPTIONS_DOT_STR "methodjit.chrome";
|
||||||
static const char js_profiling_content_str[] = JS_OPTIONS_DOT_STR "jitprofiling.content";
|
static const char js_profiling_content_str[] = JS_OPTIONS_DOT_STR "jitprofiling.content";
|
||||||
static const char js_profiling_chrome_str[] = JS_OPTIONS_DOT_STR "jitprofiling.chrome";
|
static const char js_profiling_chrome_str[] = JS_OPTIONS_DOT_STR "jitprofiling.chrome";
|
||||||
|
static const char js_methodjit_always_str[] = JS_OPTIONS_DOT_STR "methodjit_always";
|
||||||
|
|
||||||
int
|
int
|
||||||
nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
||||||
@ -1047,6 +1048,7 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
|||||||
PRBool useProfiling = nsContentUtils::GetBoolPref(chromeWindow ?
|
PRBool useProfiling = nsContentUtils::GetBoolPref(chromeWindow ?
|
||||||
js_profiling_chrome_str :
|
js_profiling_chrome_str :
|
||||||
js_profiling_content_str);
|
js_profiling_content_str);
|
||||||
|
PRBool useMethodJITAlways = nsContentUtils::GetBoolPref(js_methodjit_always_str);
|
||||||
nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
|
nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
|
||||||
if (xr) {
|
if (xr) {
|
||||||
PRBool safeMode = PR_FALSE;
|
PRBool safeMode = PR_FALSE;
|
||||||
@ -1055,6 +1057,7 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
|||||||
useTraceJIT = PR_FALSE;
|
useTraceJIT = PR_FALSE;
|
||||||
useMethodJIT = PR_FALSE;
|
useMethodJIT = PR_FALSE;
|
||||||
useProfiling = PR_FALSE;
|
useProfiling = PR_FALSE;
|
||||||
|
useMethodJITAlways = PR_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1073,6 +1076,11 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
|||||||
else
|
else
|
||||||
newDefaultJSOptions &= ~JSOPTION_PROFILING;
|
newDefaultJSOptions &= ~JSOPTION_PROFILING;
|
||||||
|
|
||||||
|
if (useMethodJITAlways)
|
||||||
|
newDefaultJSOptions |= JSOPTION_METHODJIT_ALWAYS;
|
||||||
|
else
|
||||||
|
newDefaultJSOptions &= ~JSOPTION_METHODJIT_ALWAYS;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// In debug builds, warnings are enabled in chrome context if
|
// In debug builds, warnings are enabled in chrome context if
|
||||||
// javascript.options.strict.debug is true
|
// javascript.options.strict.debug is true
|
||||||
|
@ -93,6 +93,8 @@ class Test:
|
|||||||
test.allow_oom = True
|
test.allow_oom = True
|
||||||
elif name == 'valgrind':
|
elif name == 'valgrind':
|
||||||
test.valgrind = options.valgrind
|
test.valgrind = options.valgrind
|
||||||
|
elif name == 'mjitalways':
|
||||||
|
test.jitflags.append('-a')
|
||||||
else:
|
else:
|
||||||
print('warning: unrecognized |jit-test| attribute %s'%part)
|
print('warning: unrecognized |jit-test| attribute %s'%part)
|
||||||
|
|
||||||
@ -426,7 +428,7 @@ def main(argv):
|
|||||||
for test in test_list:
|
for test in test_list:
|
||||||
for jitflags in jitflags_list:
|
for jitflags in jitflags_list:
|
||||||
new_test = test.copy()
|
new_test = test.copy()
|
||||||
new_test.jitflags = jitflags
|
new_test.jitflags.extend(jitflags)
|
||||||
job_list.append(new_test)
|
job_list.append(new_test)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
setDebug(true);
|
setDebug(true);
|
||||||
|
|
||||||
function callee() {
|
function callee() {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
setDebug(true);
|
setDebug(true);
|
||||||
|
|
||||||
function callee() {
|
function callee() {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
setDebug(true);
|
setDebug(true);
|
||||||
|
|
||||||
function callee() {
|
function callee() {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
setDebug(true);
|
setDebug(true);
|
||||||
|
|
||||||
this.__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
this.__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
setDebug(true);
|
setDebug(true);
|
||||||
|
|
||||||
this.__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
this.__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
setDebug(true);
|
setDebug(true);
|
||||||
|
|
||||||
this.__defineGetter__("someProperty", function () { evalInFrame(1, "x = 'success'"); });
|
this.__defineGetter__("someProperty", function () { evalInFrame(1, "x = 'success'"); });
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
setDebug(true);
|
setDebug(true);
|
||||||
|
|
||||||
function nop(){}
|
function nop(){}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
setDebug(true);
|
setDebug(true);
|
||||||
|
|
||||||
function nop(){}
|
function nop(){}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
setDebug(true);
|
setDebug(true);
|
||||||
|
|
||||||
function nop(){}
|
function nop(){}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// |jit-test| mjitalways
|
||||||
// vim: set ts=4 sw=4 tw=99 et:
|
// vim: set ts=4 sw=4 tw=99 et:
|
||||||
|
|
||||||
function assertObjectsEqual(obj1, obj2) {
|
function assertObjectsEqual(obj1, obj2) {
|
||||||
|
@ -955,11 +955,14 @@ JS_StringToVersion(const char *string);
|
|||||||
|
|
||||||
#define JSOPTION_METHODJIT JS_BIT(14) /* Whole-method JIT. */
|
#define JSOPTION_METHODJIT JS_BIT(14) /* Whole-method JIT. */
|
||||||
#define JSOPTION_PROFILING JS_BIT(15) /* Profiler to make tracer/methodjit choices. */
|
#define JSOPTION_PROFILING JS_BIT(15) /* Profiler to make tracer/methodjit choices. */
|
||||||
|
#define JSOPTION_METHODJIT_ALWAYS \
|
||||||
|
JS_BIT(16) /* Always whole-method JIT,
|
||||||
|
don't tune at run-time. */
|
||||||
|
|
||||||
/* Options which reflect compile-time properties of scripts. */
|
/* Options which reflect compile-time properties of scripts. */
|
||||||
#define JSCOMPILEOPTION_MASK (JSOPTION_XML | JSOPTION_ANONFUNFIX)
|
#define JSCOMPILEOPTION_MASK (JSOPTION_XML | JSOPTION_ANONFUNFIX)
|
||||||
|
|
||||||
#define JSRUNOPTION_MASK (JS_BITMASK(16) & ~JSCOMPILEOPTION_MASK)
|
#define JSRUNOPTION_MASK (JS_BITMASK(17) & ~JSCOMPILEOPTION_MASK)
|
||||||
#define JSALLOPTION_MASK (JSCOMPILEOPTION_MASK | JSRUNOPTION_MASK)
|
#define JSALLOPTION_MASK (JSCOMPILEOPTION_MASK | JSRUNOPTION_MASK)
|
||||||
|
|
||||||
extern JS_PUBLIC_API(uint32)
|
extern JS_PUBLIC_API(uint32)
|
||||||
|
@ -154,10 +154,12 @@ JSCompartment::init()
|
|||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
if (!backEdgeTable.init())
|
||||||
if (!(jaegerCompartment = js_new<mjit::JaegerCompartment>())) {
|
return false;
|
||||||
|
|
||||||
|
#ifdef JS_METHODJIT
|
||||||
|
if (!(jaegerCompartment = js_new<mjit::JaegerCompartment>()))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
return jaegerCompartment->Initialize();
|
return jaegerCompartment->Initialize();
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
@ -573,3 +575,25 @@ JSCompartment::allocMathCache(JSContext *cx)
|
|||||||
js_ReportOutOfMemory(cx);
|
js_ReportOutOfMemory(cx);
|
||||||
return mathCache;
|
return mathCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
JSCompartment::backEdgeCount(jsbytecode *pc) const
|
||||||
|
{
|
||||||
|
if (BackEdgeMap::Ptr p = backEdgeTable.lookup(pc))
|
||||||
|
return p->value;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
JSCompartment::incBackEdgeCount(jsbytecode *pc)
|
||||||
|
{
|
||||||
|
if (BackEdgeMap::AddPtr p = backEdgeTable.lookupForAdd(pc)) {
|
||||||
|
p->value++;
|
||||||
|
return p->value;
|
||||||
|
} else {
|
||||||
|
backEdgeTable.add(p, pc, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -482,6 +482,13 @@ struct JS_FRIEND_API(JSCompartment) {
|
|||||||
|
|
||||||
bool marked;
|
bool marked;
|
||||||
|
|
||||||
|
typedef js::HashMap<jsbytecode*,
|
||||||
|
size_t,
|
||||||
|
js::DefaultHasher<jsbytecode*>,
|
||||||
|
js::SystemAllocPolicy> BackEdgeMap;
|
||||||
|
|
||||||
|
BackEdgeMap backEdgeTable;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
js::MathCache *getMathCache(JSContext *cx) {
|
js::MathCache *getMathCache(JSContext *cx) {
|
||||||
return mathCache ? mathCache : allocMathCache(cx);
|
return mathCache ? mathCache : allocMathCache(cx);
|
||||||
@ -489,6 +496,9 @@ struct JS_FRIEND_API(JSCompartment) {
|
|||||||
|
|
||||||
bool isMarked() { return marked; }
|
bool isMarked() { return marked; }
|
||||||
void clearMark() { marked = false; }
|
void clearMark() { marked = false; }
|
||||||
|
|
||||||
|
size_t backEdgeCount(jsbytecode *pc) const;
|
||||||
|
size_t incBackEdgeCount(jsbytecode *pc);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define JS_SCRIPTS_TO_GC(cx) ((cx)->compartment->scriptsToGC)
|
#define JS_SCRIPTS_TO_GC(cx) ((cx)->compartment->scriptsToGC)
|
||||||
|
@ -76,6 +76,7 @@
|
|||||||
#include "jslibmath.h"
|
#include "jslibmath.h"
|
||||||
#include "jsvector.h"
|
#include "jsvector.h"
|
||||||
#include "methodjit/MethodJIT.h"
|
#include "methodjit/MethodJIT.h"
|
||||||
|
#include "methodjit/MethodJIT-inl.h"
|
||||||
#include "methodjit/Logging.h"
|
#include "methodjit/Logging.h"
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
@ -629,7 +630,8 @@ RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp)
|
|||||||
JS_ASSERT(fp->script() == script);
|
JS_ASSERT(fp->script() == script);
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, fp);
|
mjit::CompileStatus status =
|
||||||
|
mjit::CanMethodJIT(cx, script, fp, mjit::CompileRequest_Interpreter);
|
||||||
if (status == mjit::Compile_Error)
|
if (status == mjit::Compile_Error)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
@ -772,7 +774,7 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
|
|||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
/* Hoist dynamic checks from RunScript. */
|
/* Hoist dynamic checks from RunScript. */
|
||||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script_, fp);
|
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script_, fp, mjit::CompileRequest_JIT);
|
||||||
if (status == mjit::Compile_Error)
|
if (status == mjit::Compile_Error)
|
||||||
return false;
|
return false;
|
||||||
if (status != mjit::Compile_Okay)
|
if (status != mjit::Compile_Okay)
|
||||||
@ -2322,6 +2324,30 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||||||
#define LOAD_DOUBLE(PCOFF, dbl) \
|
#define LOAD_DOUBLE(PCOFF, dbl) \
|
||||||
(dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble())
|
(dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble())
|
||||||
|
|
||||||
|
#ifdef JS_METHODJIT
|
||||||
|
|
||||||
|
#define MONITOR_BRANCH_METHODJIT() \
|
||||||
|
JS_BEGIN_MACRO \
|
||||||
|
mjit::CompileStatus status = \
|
||||||
|
mjit::CanMethodJITAtBranch(cx, script, regs.fp, regs.pc); \
|
||||||
|
if (status == mjit::Compile_Error) \
|
||||||
|
goto error; \
|
||||||
|
if (status == mjit::Compile_Okay) { \
|
||||||
|
void *ncode = \
|
||||||
|
script->nativeCodeForPC(regs.fp->isConstructing(), regs.pc); \
|
||||||
|
interpReturnOK = mjit::JaegerShotAtSafePoint(cx, ncode); \
|
||||||
|
if (inlineCallCount) \
|
||||||
|
goto jit_return; \
|
||||||
|
goto leave_on_safe_point; \
|
||||||
|
} \
|
||||||
|
JS_END_MACRO
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define MONITOR_BRANCH_METHODJIT() ((void) 0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
|
|
||||||
#ifdef MOZ_TRACEVIS
|
#ifdef MOZ_TRACEVIS
|
||||||
@ -2354,6 +2380,11 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||||||
#define MONITOR_BRANCH() \
|
#define MONITOR_BRANCH() \
|
||||||
JS_BEGIN_MACRO \
|
JS_BEGIN_MACRO \
|
||||||
if (TRACING_ENABLED(cx)) { \
|
if (TRACING_ENABLED(cx)) { \
|
||||||
|
if (!TRACE_RECORDER(cx) && !TRACE_PROFILER(cx) && \
|
||||||
|
interpMode == JSINTERP_NORMAL) \
|
||||||
|
{ \
|
||||||
|
MONITOR_BRANCH_METHODJIT(); \
|
||||||
|
} else { \
|
||||||
MonitorResult r = MonitorLoopEdge(cx, inlineCallCount); \
|
MonitorResult r = MonitorLoopEdge(cx, inlineCallCount); \
|
||||||
if (r == MONITOR_RECORDING) { \
|
if (r == MONITOR_RECORDING) { \
|
||||||
JS_ASSERT(TRACE_RECORDER(cx)); \
|
JS_ASSERT(TRACE_RECORDER(cx)); \
|
||||||
@ -2367,6 +2398,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||||||
if (r == MONITOR_ERROR) \
|
if (r == MONITOR_ERROR) \
|
||||||
goto error; \
|
goto error; \
|
||||||
} \
|
} \
|
||||||
|
} \
|
||||||
JS_END_MACRO
|
JS_END_MACRO
|
||||||
|
|
||||||
#else /* !JS_TRACER */
|
#else /* !JS_TRACER */
|
||||||
@ -4693,7 +4725,10 @@ BEGIN_CASE(JSOP_FUNCALL)
|
|||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
/* Try to ensure methods are method JIT'd. */
|
/* Try to ensure methods are method JIT'd. */
|
||||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, regs.fp);
|
mjit::CompileRequest request = (interpMode == JSINTERP_NORMAL)
|
||||||
|
? mjit::CompileRequest_Interpreter
|
||||||
|
: mjit::CompileRequest_JIT;
|
||||||
|
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, regs.fp, request);
|
||||||
if (status == mjit::Compile_Error)
|
if (status == mjit::Compile_Error)
|
||||||
goto error;
|
goto error;
|
||||||
if (!TRACE_RECORDER(cx) && !TRACE_PROFILER(cx) && status == mjit::Compile_Okay) {
|
if (!TRACE_RECORDER(cx) && !TRACE_PROFILER(cx) && status == mjit::Compile_Okay) {
|
||||||
@ -6920,7 +6955,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||||||
* This path is used when it's guaranteed the method can be finished
|
* This path is used when it's guaranteed the method can be finished
|
||||||
* inside the JIT.
|
* inside the JIT.
|
||||||
*/
|
*/
|
||||||
#if defined(JS_TRACER) && defined(JS_METHODJIT)
|
#if defined(JS_METHODJIT)
|
||||||
leave_on_safe_point:
|
leave_on_safe_point:
|
||||||
#endif
|
#endif
|
||||||
return interpReturnOK;
|
return interpReturnOK;
|
||||||
|
@ -373,6 +373,8 @@ struct JSScript {
|
|||||||
private:
|
private:
|
||||||
uint16 version; /* JS version under which script was compiled */
|
uint16 version; /* JS version under which script was compiled */
|
||||||
|
|
||||||
|
size_t callCount_; /* Number of times the script has been called. */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint16 nfixed; /* number of slots besides stack operands in
|
uint16 nfixed; /* number of slots besides stack operands in
|
||||||
slot array */
|
slot array */
|
||||||
@ -473,6 +475,9 @@ struct JSScript {
|
|||||||
return constructing ? jitCtor : jitNormal;
|
return constructing ? jitCtor : jitNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t callCount() const { return callCount_; }
|
||||||
|
size_t incCallCount() { return ++callCount_; }
|
||||||
|
|
||||||
JITScriptStatus getJITStatus(bool constructing) {
|
JITScriptStatus getJITStatus(bool constructing) {
|
||||||
void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;
|
void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;
|
||||||
if (addr == NULL)
|
if (addr == NULL)
|
||||||
|
@ -645,7 +645,8 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
|||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
jitTraceICs[i].loopCounterStart = GetHotloop(cx);
|
jitTraceICs[i].loopCounterStart = GetHotloop(cx);
|
||||||
#endif
|
#endif
|
||||||
jitTraceICs[i].loopCounter = jitTraceICs[i].loopCounterStart;
|
jitTraceICs[i].loopCounter = jitTraceICs[i].loopCounterStart
|
||||||
|
- cx->compartment->backEdgeCount(traceICs[i].jumpTarget);
|
||||||
|
|
||||||
stubCode.patch(traceICs[i].addrLabel, &jitTraceICs[i]);
|
stubCode.patch(traceICs[i].addrLabel, &jitTraceICs[i]);
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
#include "StubCalls-inl.h"
|
#include "StubCalls-inl.h"
|
||||||
|
#include "MethodJIT-inl.h"
|
||||||
|
|
||||||
#include "jsautooplen.h"
|
#include "jsautooplen.h"
|
||||||
|
|
||||||
@ -170,12 +171,7 @@ top:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up a frame and return. popFrame indicates whether to additionally pop
|
* Clean up a frame and return.
|
||||||
* the frame and store the return value on the caller's stack. The frame will
|
|
||||||
* normally be popped by the caller on return from a call into JIT code,
|
|
||||||
* so must be popped here when that caller code will not execute. This can be
|
|
||||||
* either because of a call into an un-JITable script, or because the call is
|
|
||||||
* throwing an exception.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
InlineReturn(VMFrame &f)
|
InlineReturn(VMFrame &f)
|
||||||
@ -311,8 +307,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* FixupArity/RemovePartialFrame expect to be called after the early
|
* FixupArity/RemovePartialFrame expect to be called after the early
|
||||||
* prologue. Pass the existing value for ncode, it has already been set
|
* prologue.
|
||||||
* by the jit code calling into this stub.
|
|
||||||
*/
|
*/
|
||||||
fp->initCallFrameEarlyPrologue(fun, nactual);
|
fp->initCallFrameEarlyPrologue(fun, nactual);
|
||||||
|
|
||||||
@ -333,7 +328,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||||||
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
|
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
|
|
||||||
CompileStatus status = CanMethodJIT(cx, script, fp);
|
CompileStatus status = CanMethodJIT(cx, script, fp, CompileRequest_JIT);
|
||||||
if (status == Compile_Okay)
|
if (status == Compile_Okay)
|
||||||
return script->getJIT(fp->isConstructing())->invokeEntry;
|
return script->getJIT(fp->isConstructing())->invokeEntry;
|
||||||
|
|
||||||
@ -348,7 +343,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
Value *vp = f.regs.sp - (argc + 2);
|
Value *vp = f.regs.sp - (argc + 2);
|
||||||
@ -380,11 +375,14 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
|||||||
|
|
||||||
/* Try to compile if not already compiled. */
|
/* Try to compile if not already compiled. */
|
||||||
if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) {
|
if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) {
|
||||||
if (mjit::TryCompile(cx, newfp) == Compile_Error) {
|
CompileStatus status = CanMethodJIT(cx, newscript, newfp, CompileRequest_Interpreter);
|
||||||
|
if (status == Compile_Error) {
|
||||||
/* A runtime exception was thrown, get out. */
|
/* A runtime exception was thrown, get out. */
|
||||||
InlineReturn(f);
|
InlineReturn(f);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (status == Compile_Abort)
|
||||||
|
*unjittable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If newscript was successfully compiled, run it. */
|
/* If newscript was successfully compiled, run it. */
|
||||||
@ -420,7 +418,7 @@ stubs::UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
|||||||
/* Try to do a fast inline call before the general Invoke path. */
|
/* Try to do a fast inline call before the general Invoke path. */
|
||||||
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted()) {
|
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted()) {
|
||||||
ucr->callee = &vp->toObject();
|
ucr->callee = &vp->toObject();
|
||||||
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, argc))
|
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, &ucr->unjittable, argc))
|
||||||
THROW();
|
THROW();
|
||||||
} else {
|
} else {
|
||||||
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
|
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
|
||||||
@ -470,7 +468,7 @@ stubs::UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
|||||||
ucr->fun = GET_FUNCTION_PRIVATE(cx, ucr->callee);
|
ucr->fun = GET_FUNCTION_PRIVATE(cx, ucr->callee);
|
||||||
|
|
||||||
if (ucr->fun->isInterpreted()) {
|
if (ucr->fun->isInterpreted()) {
|
||||||
if (!UncachedInlineCall(f, 0, &ucr->codeAddr, argc))
|
if (!UncachedInlineCall(f, 0, &ucr->codeAddr, &ucr->unjittable, argc))
|
||||||
THROW();
|
THROW();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
105
js/src/methodjit/MethodJIT-inl.h
Normal file
105
js/src/methodjit/MethodJIT-inl.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* vim: set ts=4 sw=4 et tw=99:
|
||||||
|
*
|
||||||
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||||
|
* May 28, 2008.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Brendan Eich <brendan@mozilla.org>
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* David Anderson <danderson@mozilla.com>
|
||||||
|
* David Mandelin <dmandelin@mozilla.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#if !defined jsjaeger_methodjit_inl_h__ && defined JS_METHODJIT
|
||||||
|
#define jsjaeger_methodjit_inl_h__
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
namespace mjit {
|
||||||
|
|
||||||
|
enum CompileRequest
|
||||||
|
{
|
||||||
|
CompileRequest_Interpreter,
|
||||||
|
CompileRequest_JIT
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Number of times a script must be called before we run it in the methodjit. */
|
||||||
|
static const size_t CALLS_BEFORE_COMPILE = 16;
|
||||||
|
|
||||||
|
/* Number of loop back-edges we execute in the interpreter before methodjitting. */
|
||||||
|
static const size_t BACKEDGES_BEFORE_COMPILE = 16;
|
||||||
|
|
||||||
|
static inline CompileStatus
|
||||||
|
CanMethodJIT(JSContext *cx, JSScript *script, JSStackFrame *fp, CompileRequest request)
|
||||||
|
{
|
||||||
|
if (!cx->methodJitEnabled)
|
||||||
|
return Compile_Abort;
|
||||||
|
JITScriptStatus status = script->getJITStatus(fp->isConstructing());
|
||||||
|
if (status == JITScript_Invalid)
|
||||||
|
return Compile_Abort;
|
||||||
|
if (request == CompileRequest_Interpreter &&
|
||||||
|
status == JITScript_None &&
|
||||||
|
!cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) &&
|
||||||
|
script->incCallCount() <= CALLS_BEFORE_COMPILE)
|
||||||
|
{
|
||||||
|
return Compile_Skipped;
|
||||||
|
}
|
||||||
|
if (status == JITScript_None)
|
||||||
|
return TryCompile(cx, fp);
|
||||||
|
return Compile_Okay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called from a backedge in the interpreter to decide if we should transition to the
|
||||||
|
* methodjit. If so, we compile the given function.
|
||||||
|
*/
|
||||||
|
static inline CompileStatus
|
||||||
|
CanMethodJITAtBranch(JSContext *cx, JSScript *script, JSStackFrame *fp, jsbytecode *pc)
|
||||||
|
{
|
||||||
|
if (!cx->methodJitEnabled)
|
||||||
|
return Compile_Abort;
|
||||||
|
JITScriptStatus status = script->getJITStatus(fp->isConstructing());
|
||||||
|
if (status == JITScript_Invalid)
|
||||||
|
return Compile_Abort;
|
||||||
|
if (status == JITScript_None &&
|
||||||
|
!cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) &&
|
||||||
|
cx->compartment->incBackEdgeCount(pc) <= BACKEDGES_BEFORE_COMPILE)
|
||||||
|
{
|
||||||
|
return Compile_Skipped;
|
||||||
|
}
|
||||||
|
if (status == JITScript_None)
|
||||||
|
return TryCompile(cx, fp);
|
||||||
|
return Compile_Okay;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -394,7 +394,8 @@ enum CompileStatus
|
|||||||
{
|
{
|
||||||
Compile_Okay,
|
Compile_Okay,
|
||||||
Compile_Abort,
|
Compile_Abort,
|
||||||
Compile_Error
|
Compile_Error,
|
||||||
|
Compile_Skipped
|
||||||
};
|
};
|
||||||
|
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
@ -406,19 +407,6 @@ TryCompile(JSContext *cx, JSStackFrame *fp);
|
|||||||
void
|
void
|
||||||
ReleaseScriptCode(JSContext *cx, JSScript *script);
|
ReleaseScriptCode(JSContext *cx, JSScript *script);
|
||||||
|
|
||||||
static inline CompileStatus
|
|
||||||
CanMethodJIT(JSContext *cx, JSScript *script, JSStackFrame *fp)
|
|
||||||
{
|
|
||||||
if (!cx->methodJitEnabled)
|
|
||||||
return Compile_Abort;
|
|
||||||
JITScriptStatus status = script->getJITStatus(fp->isConstructing());
|
|
||||||
if (status == JITScript_Invalid)
|
|
||||||
return Compile_Abort;
|
|
||||||
if (status == JITScript_None)
|
|
||||||
return TryCompile(cx, fp);
|
|
||||||
return Compile_Okay;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CallSite
|
struct CallSite
|
||||||
{
|
{
|
||||||
uint32 codeOffset;
|
uint32 codeOffset;
|
||||||
|
@ -950,6 +950,7 @@ class CallCompiler : public BaseCompiler
|
|||||||
// If the function cannot be jitted (generally unjittable or empty script),
|
// If the function cannot be jitted (generally unjittable or empty script),
|
||||||
// patch this site to go to a slow path always.
|
// patch this site to go to a slow path always.
|
||||||
if (!ucr.codeAddr) {
|
if (!ucr.codeAddr) {
|
||||||
|
if (ucr.unjittable)
|
||||||
disable(jit);
|
disable(jit);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ void JS_FASTCALL LeaveScript(VMFrame &f);
|
|||||||
* These functions can have one of two results:
|
* These functions can have one of two results:
|
||||||
*
|
*
|
||||||
* (1) The function was executed in the interpreter. Then all fields
|
* (1) The function was executed in the interpreter. Then all fields
|
||||||
* are NULL.
|
* are NULL except unjittable.
|
||||||
*
|
*
|
||||||
* (2) The function was not executed, and the function has been compiled
|
* (2) The function was not executed, and the function has been compiled
|
||||||
* to JM native code. Then all fields are non-NULL.
|
* to JM native code. Then all fields are non-NULL.
|
||||||
@ -89,11 +89,13 @@ struct UncachedCallResult {
|
|||||||
JSObject *callee; // callee object
|
JSObject *callee; // callee object
|
||||||
JSFunction *fun; // callee function
|
JSFunction *fun; // callee function
|
||||||
void *codeAddr; // code address of compiled callee function
|
void *codeAddr; // code address of compiled callee function
|
||||||
|
bool unjittable; // did we try to JIT and fail?
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
callee = NULL;
|
callee = NULL;
|
||||||
fun = NULL;
|
fun = NULL;
|
||||||
codeAddr = NULL;
|
codeAddr = NULL;
|
||||||
|
unjittable = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -582,6 +582,8 @@ usage(void)
|
|||||||
" -i Enable interactive read-eval-print loop\n"
|
" -i Enable interactive read-eval-print loop\n"
|
||||||
" -j Enable the TraceMonkey tracing JIT\n"
|
" -j Enable the TraceMonkey tracing JIT\n"
|
||||||
" -m Enable the JaegerMonkey method JIT\n"
|
" -m Enable the JaegerMonkey method JIT\n"
|
||||||
|
" -a Always method JIT, ignore internal tuning\n"
|
||||||
|
" This only has effect with -m\n"
|
||||||
" -p Enable loop profiling for TraceMonkey\n"
|
" -p Enable loop profiling for TraceMonkey\n"
|
||||||
" -d Enable debug mode\n"
|
" -d Enable debug mode\n"
|
||||||
" -b Print timing statistics\n"
|
" -b Print timing statistics\n"
|
||||||
@ -634,9 +636,10 @@ static const struct {
|
|||||||
} js_options[] = {
|
} js_options[] = {
|
||||||
{"anonfunfix", JSOPTION_ANONFUNFIX},
|
{"anonfunfix", JSOPTION_ANONFUNFIX},
|
||||||
{"atline", JSOPTION_ATLINE},
|
{"atline", JSOPTION_ATLINE},
|
||||||
|
{"jitprofiling", JSOPTION_PROFILING},
|
||||||
{"tracejit", JSOPTION_JIT},
|
{"tracejit", JSOPTION_JIT},
|
||||||
{"methodjit", JSOPTION_METHODJIT},
|
{"methodjit", JSOPTION_METHODJIT},
|
||||||
{"jitprofiling", JSOPTION_PROFILING},
|
{"methodjit_always",JSOPTION_METHODJIT_ALWAYS},
|
||||||
{"relimit", JSOPTION_RELIMIT},
|
{"relimit", JSOPTION_RELIMIT},
|
||||||
{"strict", JSOPTION_STRICT},
|
{"strict", JSOPTION_STRICT},
|
||||||
{"werror", JSOPTION_WERROR},
|
{"werror", JSOPTION_WERROR},
|
||||||
@ -807,6 +810,10 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
|
|||||||
JS_ToggleOptions(cx, JSOPTION_METHODJIT);
|
JS_ToggleOptions(cx, JSOPTION_METHODJIT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
JS_ToggleOptions(cx, JSOPTION_METHODJIT_ALWAYS);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
enableProfiling = !enableProfiling;
|
enableProfiling = !enableProfiling;
|
||||||
JS_ToggleOptions(cx, JSOPTION_PROFILING);
|
JS_ToggleOptions(cx, JSOPTION_PROFILING);
|
||||||
|
@ -650,7 +650,8 @@ function optionsClear() {
|
|||||||
if (optionName &&
|
if (optionName &&
|
||||||
optionName != "methodjit" &&
|
optionName != "methodjit" &&
|
||||||
optionName != "tracejit" &&
|
optionName != "tracejit" &&
|
||||||
optionName != "jitprofiling")
|
optionName != "jitprofiling" &&
|
||||||
|
optionName != "methodjit_always")
|
||||||
{
|
{
|
||||||
options(optionName);
|
options(optionName);
|
||||||
}
|
}
|
||||||
|
@ -33,5 +33,6 @@ user_pref("javascript.options.methodjit.chrome", false);
|
|||||||
user_pref("javascript.options.methodjit.content", true);
|
user_pref("javascript.options.methodjit.content", true);
|
||||||
user_pref("javascript.options.jitprofiling.chrome", false);
|
user_pref("javascript.options.jitprofiling.chrome", false);
|
||||||
user_pref("javascript.options.jitprofiling.content", true);
|
user_pref("javascript.options.jitprofiling.content", true);
|
||||||
|
user_pref("javascript.options.methodjit_always", false);
|
||||||
user_pref("javascript.options.strict", false);
|
user_pref("javascript.options.strict", false);
|
||||||
user_pref("javascript.options.werror", false);
|
user_pref("javascript.options.werror", false);
|
||||||
|
@ -604,6 +604,7 @@ pref("javascript.options.methodjit.content", true);
|
|||||||
pref("javascript.options.methodjit.chrome", false);
|
pref("javascript.options.methodjit.chrome", false);
|
||||||
pref("javascript.options.jitprofiling.content", true);
|
pref("javascript.options.jitprofiling.content", true);
|
||||||
pref("javascript.options.jitprofiling.chrome", false);
|
pref("javascript.options.jitprofiling.chrome", false);
|
||||||
|
pref("javascript.options.methodjit_always", false);
|
||||||
// This preference limits the memory usage of javascript.
|
// This preference limits the memory usage of javascript.
|
||||||
// If you want to change these values for your device,
|
// If you want to change these values for your device,
|
||||||
// please find Bug 417052 comment 17 and Bug 456721
|
// please find Bug 417052 comment 17 and Bug 456721
|
||||||
|
Loading…
Reference in New Issue
Block a user