mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 12:55:46 +00:00
Bug 538293 - remove inlineCallCount and this STACK_QUOTA silliness (r=dvander)
--HG-- extra : rebase_source : 724910c67423b0720ca5c3732699bca4d64324ef
This commit is contained in:
parent
a0b946dbbc
commit
9f59f7c3f5
@ -1,10 +1,11 @@
|
||||
var Q = 0;
|
||||
var thrown = false;
|
||||
try {
|
||||
(function f(i) { Q = i; if (i == 100000) return; f(i+1); })(1)
|
||||
(function f(i) { Q = i; if (i == 200000) return; f(i+1); })(1)
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
|
||||
// Exact behavior of recursion check depends on which JIT we use.
|
||||
var ok = (Q == 3000 || Q == 3001);
|
||||
assertEq(ok, true);
|
||||
assertEq(thrown && Q > 10000, true);
|
||||
|
||||
|
@ -3,7 +3,7 @@ try {
|
||||
Function("\
|
||||
(function f() {\
|
||||
({x:{b}}=x);\
|
||||
f()\
|
||||
f.apply(null, new Array(100))\
|
||||
})()\
|
||||
")()
|
||||
} catch (e) {
|
||||
|
@ -3,7 +3,7 @@ try {
|
||||
Function("\
|
||||
(function f() {\
|
||||
({x}=x);\
|
||||
f()\
|
||||
f.apply(null, new Array(100))\
|
||||
})()\
|
||||
")()
|
||||
} catch (e) {
|
||||
|
11
js/src/jit-test/tests/basic/test-apply-many-args.js
Normal file
11
js/src/jit-test/tests/basic/test-apply-many-args.js
Normal file
@ -0,0 +1,11 @@
|
||||
function f(x) {
|
||||
if (x == 0)
|
||||
return;
|
||||
arguments[0]--;
|
||||
f.apply(null, arguments);
|
||||
}
|
||||
|
||||
a = [100];
|
||||
for (var i = 0; i < 2000; ++i)
|
||||
a.push(i);
|
||||
f.apply(null, a);
|
@ -767,10 +767,10 @@ PopulateReportBlame(JSContext *cx, JSErrorReport *report)
|
||||
* Walk stack until we find a frame that is associated with some script
|
||||
* rather than a native frame.
|
||||
*/
|
||||
for (StackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
|
||||
if (fp->pc(cx)) {
|
||||
report->filename = fp->script()->filename;
|
||||
report->lineno = js_FramePCToLineNumber(cx, fp);
|
||||
for (FrameRegsIter iter(cx); !iter.done(); ++iter) {
|
||||
if (iter.fp()->isScriptFrame()) {
|
||||
report->filename = iter.fp()->script()->filename;
|
||||
report->lineno = js_FramePCToLineNumber(cx, iter.fp(), iter.pc());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1459,13 +1459,6 @@ class AutoCheckRequestDepth {
|
||||
# define CHECK_REQUEST_THREAD(cx) ((void) 0)
|
||||
#endif
|
||||
|
||||
static inline uintN
|
||||
FramePCOffset(JSContext *cx, js::StackFrame* fp)
|
||||
{
|
||||
jsbytecode *pc = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
|
||||
return uintN(pc - fp->script()->code);
|
||||
}
|
||||
|
||||
static inline JSAtom **
|
||||
FrameAtomBase(JSContext *cx, js::StackFrame *fp)
|
||||
{
|
||||
|
@ -102,7 +102,6 @@ struct TracerState
|
||||
void* rpAtLastTreeCall; // value of rp at innermost tree call guard
|
||||
VMSideExit* outermostTreeExitGuard; // the last side exit returned by js_CallTree
|
||||
TreeFragment* outermostTree; // the outermost tree we initially invoked
|
||||
uintN* inlineCallCountp; // inline call count counter
|
||||
VMSideExit** innermostNestedGuardp;
|
||||
VMSideExit* innermost;
|
||||
uint64 startTime;
|
||||
@ -121,7 +120,7 @@ struct TracerState
|
||||
js::Value* nativeVp;
|
||||
|
||||
TracerState(JSContext *cx, TraceMonitor *tm, TreeFragment *ti,
|
||||
uintN &inlineCallCountp, VMSideExit** innermostNestedGuardp);
|
||||
VMSideExit** innermostNestedGuardp);
|
||||
~TracerState();
|
||||
};
|
||||
|
||||
|
@ -1429,7 +1429,7 @@ JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
|
||||
JS_PUBLIC_API(jsbytecode *)
|
||||
JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
return Valueify(fp)->pc(cx);
|
||||
return Valueify(fp)->pcQuadratic(cx);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSStackFrame *)
|
||||
@ -2483,9 +2483,9 @@ jstv_Filename(JSStackFrame *fp)
|
||||
inline uintN
|
||||
jstv_Lineno(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
while (fp && fp->pc(cx) == NULL)
|
||||
while (fp && fp->pcQuadratic(cx) == NULL)
|
||||
fp = fp->prev();
|
||||
return (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0;
|
||||
return (fp && fp->pcQuadratic(cx)) ? js_FramePCToLineNumber(cx, fp) : 0;
|
||||
}
|
||||
|
||||
/* Collect states here and distribute to a matching buffer, if any */
|
||||
|
@ -267,7 +267,6 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
||||
JSErrorReporter older;
|
||||
JSExceptionState *state;
|
||||
jsid callerid;
|
||||
StackFrame *fp, *fpstop;
|
||||
size_t stackDepth, valueCount, size;
|
||||
JSBool overflow;
|
||||
JSExnPrivate *priv;
|
||||
@ -293,7 +292,10 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
||||
callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom);
|
||||
stackDepth = 0;
|
||||
valueCount = 0;
|
||||
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
|
||||
|
||||
FrameRegsIter firstPass(cx);
|
||||
for (; !firstPass.done(); ++firstPass) {
|
||||
StackFrame *fp = firstPass.fp();
|
||||
if (fp->compartment() != cx->compartment)
|
||||
break;
|
||||
if (fp->isNonEvalFunctionFrame()) {
|
||||
@ -308,7 +310,6 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
||||
}
|
||||
JS_RestoreExceptionState(cx, state);
|
||||
JS_SetErrorReporter(cx, older);
|
||||
fpstop = fp;
|
||||
|
||||
size = offsetof(JSExnPrivate, stackElems);
|
||||
overflow = (stackDepth > ((size_t)-1 - size) / sizeof(JSStackTraceElem));
|
||||
@ -336,10 +337,11 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
||||
|
||||
values = GetStackTraceValueBuffer(priv);
|
||||
elem = priv->stackElems;
|
||||
for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->prev()) {
|
||||
for (FrameRegsIter iter(cx); iter != firstPass; ++iter) {
|
||||
StackFrame *fp = iter.fp();
|
||||
if (fp->compartment() != cx->compartment)
|
||||
break;
|
||||
if (!fp->isFunctionFrame() || fp->isEvalFrame()) {
|
||||
if (!fp->isNonEvalFunctionFrame()) {
|
||||
elem->funName = NULL;
|
||||
elem->argc = 0;
|
||||
} else {
|
||||
@ -354,8 +356,8 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
||||
elem->filename = NULL;
|
||||
if (fp->isScriptFrame()) {
|
||||
elem->filename = fp->script()->filename;
|
||||
if (fp->pc(cx))
|
||||
elem->ulineno = js_FramePCToLineNumber(cx, fp);
|
||||
if (fp->isScriptFrame())
|
||||
elem->ulineno = js_FramePCToLineNumber(cx, fp, iter.pc());
|
||||
}
|
||||
++elem;
|
||||
}
|
||||
@ -692,9 +694,6 @@ FilenameToString(JSContext *cx, const char *filename)
|
||||
static JSBool
|
||||
Exception(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *message, *filename;
|
||||
StackFrame *fp;
|
||||
|
||||
/*
|
||||
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
|
||||
* called as functions, without operator new. But as we do not give
|
||||
@ -726,6 +725,7 @@ Exception(JSContext *cx, uintN argc, Value *vp)
|
||||
|
||||
/* Set the 'message' property. */
|
||||
Value *argv = vp + 2;
|
||||
JSString *message;
|
||||
if (argc != 0 && !argv[0].isUndefined()) {
|
||||
message = js_ValueToString(cx, argv[0]);
|
||||
if (!message)
|
||||
@ -735,17 +735,21 @@ Exception(JSContext *cx, uintN argc, Value *vp)
|
||||
message = NULL;
|
||||
}
|
||||
|
||||
/* Find the scripted caller. */
|
||||
FrameRegsIter iter(cx);
|
||||
while (!iter.done() && !iter.fp()->isScriptFrame())
|
||||
++iter;
|
||||
|
||||
/* Set the 'fileName' property. */
|
||||
JSString *filename;
|
||||
if (argc > 1) {
|
||||
filename = js_ValueToString(cx, argv[1]);
|
||||
if (!filename)
|
||||
return JS_FALSE;
|
||||
argv[1].setString(filename);
|
||||
fp = NULL;
|
||||
} else {
|
||||
fp = js_GetScriptedCaller(cx, NULL);
|
||||
if (fp) {
|
||||
filename = FilenameToString(cx, fp->script()->filename);
|
||||
if (!iter.done()) {
|
||||
filename = FilenameToString(cx, iter.fp()->script()->filename);
|
||||
if (!filename)
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
@ -759,9 +763,7 @@ Exception(JSContext *cx, uintN argc, Value *vp)
|
||||
if (!ValueToECMAUint32(cx, argv[2], &lineno))
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
if (!fp)
|
||||
fp = js_GetScriptedCaller(cx, NULL);
|
||||
lineno = (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0;
|
||||
lineno = iter.done() ? 0 : js_FramePCToLineNumber(cx, iter.fp(), iter.pc());
|
||||
}
|
||||
|
||||
if (obj->getClass() == &js_ErrorClass &&
|
||||
|
@ -149,7 +149,7 @@ js::GetBlockChain(JSContext *cx, StackFrame *fp)
|
||||
return NULL;
|
||||
|
||||
/* Assume that imacros don't affect blockChain */
|
||||
jsbytecode *target = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
|
||||
jsbytecode *target = fp->hasImacropc() ? fp->imacropc() : fp->pcQuadratic(cx);
|
||||
|
||||
JSScript *script = fp->script();
|
||||
jsbytecode *start = script->code;
|
||||
@ -195,7 +195,7 @@ JSObject *
|
||||
js::GetBlockChainFast(JSContext *cx, StackFrame *fp, JSOp op, size_t oplen)
|
||||
{
|
||||
/* Assume that we're in a script frame. */
|
||||
jsbytecode *pc = fp->pc(cx);
|
||||
jsbytecode *pc = fp->pcQuadratic(cx);
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op);
|
||||
|
||||
pc += oplen;
|
||||
@ -2143,7 +2143,7 @@ IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
|
||||
namespace js {
|
||||
|
||||
JS_REQUIRES_STACK JS_NEVER_INLINE bool
|
||||
Interpret(JSContext *cx, StackFrame *entryFrame, uintN inlineCallCount, InterpMode interpMode)
|
||||
Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
{
|
||||
#ifdef MOZ_TRACEVIS
|
||||
TraceVisStateObj tvso(cx, S_INTERP);
|
||||
@ -2312,7 +2312,7 @@ Interpret(JSContext *cx, StackFrame *entryFrame, uintN inlineCallCount, InterpMo
|
||||
void *ncode = \
|
||||
script->nativeCodeForPC(regs.fp()->isConstructing(), regs.pc);\
|
||||
interpReturnOK = mjit::JaegerShotAtSafePoint(cx, ncode); \
|
||||
if (inlineCallCount) \
|
||||
if (entryFrame != regs.fp()) \
|
||||
goto jit_return; \
|
||||
regs.fp()->setFinishedInInterpreter(); \
|
||||
goto leave_on_safe_point; \
|
||||
@ -2365,7 +2365,7 @@ Interpret(JSContext *cx, StackFrame *entryFrame, uintN inlineCallCount, InterpMo
|
||||
if (!TRACE_RECORDER(cx) && !TRACE_PROFILER(cx) && useMethodJIT) { \
|
||||
MONITOR_BRANCH_METHODJIT(); \
|
||||
} else { \
|
||||
MonitorResult r = MonitorLoopEdge(cx, inlineCallCount, interpMode); \
|
||||
MonitorResult r = MonitorLoopEdge(cx, interpMode); \
|
||||
if (r == MONITOR_RECORDING) { \
|
||||
JS_ASSERT(TRACE_RECORDER(cx)); \
|
||||
JS_ASSERT(!TRACE_PROFILER(cx)); \
|
||||
@ -2856,8 +2856,6 @@ BEGIN_CASE(JSOP_STOP)
|
||||
|
||||
/* Resume execution in the calling frame. */
|
||||
RESET_USE_METHODJIT();
|
||||
JS_ASSERT(inlineCallCount);
|
||||
inlineCallCount--;
|
||||
if (JS_LIKELY(interpReturnOK)) {
|
||||
JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length
|
||||
== JSOP_CALL_LENGTH);
|
||||
@ -4618,12 +4616,6 @@ BEGIN_CASE(JSOP_FUNCALL)
|
||||
goto end_call;
|
||||
}
|
||||
|
||||
/* Restrict recursion of lightweight functions. */
|
||||
if (JS_UNLIKELY(inlineCallCount >= StackSpace::MAX_INLINE_CALLS)) {
|
||||
js_ReportOverRecursed(cx);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get pointer to new frame/slots, prepare arguments. */
|
||||
ContextStack &stack = cx->stack;
|
||||
StackFrame *newfp = stack.getInlineFrame(cx, regs.sp, argc, newfun,
|
||||
@ -4649,7 +4641,6 @@ BEGIN_CASE(JSOP_FUNCALL)
|
||||
goto error;
|
||||
|
||||
RESET_USE_METHODJIT();
|
||||
inlineCallCount++;
|
||||
JS_RUNTIME_METER(rt, inlineCalls);
|
||||
|
||||
TRACE_0(EnterFrame);
|
||||
|
@ -257,7 +257,7 @@ enum InterpMode
|
||||
* pointed to by cx->fp until completion or error.
|
||||
*/
|
||||
extern JS_REQUIRES_STACK JS_NEVER_INLINE bool
|
||||
Interpret(JSContext *cx, StackFrame *stopFp, uintN inlineCallCount = 0, InterpMode mode = JSINTERP_NORMAL);
|
||||
Interpret(JSContext *cx, StackFrame *stopFp, InterpMode mode = JSINTERP_NORMAL);
|
||||
|
||||
extern JS_REQUIRES_STACK bool
|
||||
RunScript(JSContext *cx, JSScript *script, StackFrame *fp);
|
||||
|
@ -1160,7 +1160,7 @@ EvalKernel(JSContext *cx, const CallArgs &call, EvalType evalType, StackFrame *c
|
||||
staticLevel = caller->script()->staticLevel + 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
jsbytecode *callerPC = caller->pc(cx);
|
||||
jsbytecode *callerPC = caller->pcQuadratic(cx);
|
||||
JS_ASSERT_IF(caller->isFunctionFrame(), caller->fun()->isHeavyweight());
|
||||
JS_ASSERT(callerPC && js_GetOpcode(cx, caller->script(), callerPC) == JSOP_EVAL);
|
||||
#endif
|
||||
|
@ -2070,20 +2070,19 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
token = CodeToken[op];
|
||||
|
||||
if (pc + oplen == jp->dvgfence) {
|
||||
StackFrame *fp;
|
||||
uint32 format, mode, type;
|
||||
|
||||
/*
|
||||
* Rewrite non-get ops to their "get" format if the error is in
|
||||
* the bytecode at pc, so we don't decompile more than the error
|
||||
* expression.
|
||||
*/
|
||||
fp = js_GetScriptedCaller(cx, NULL);
|
||||
format = cs->format;
|
||||
if (((fp && pc == fp->pc(cx)) ||
|
||||
FrameRegsIter iter(cx);
|
||||
while (!iter.done() && !iter.fp()->isScriptFrame())
|
||||
++iter;
|
||||
uint32 format = cs->format;
|
||||
if (((!iter.done() && pc == iter.pc()) ||
|
||||
(pc == startpc && nuses != 0)) &&
|
||||
format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_FOR|JOF_VARPROP)) {
|
||||
mode = JOF_MODE(format);
|
||||
uint32 mode = JOF_MODE(format);
|
||||
if (mode == JOF_NAME) {
|
||||
/*
|
||||
* JOF_NAME does not imply JOF_ATOM, so we must check for
|
||||
@ -2091,7 +2090,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
* JSOP_GETARG or JSOP_GETLOCAL appropriately, instead of
|
||||
* to JSOP_NAME.
|
||||
*/
|
||||
type = JOF_TYPE(format);
|
||||
uint32 type = JOF_TYPE(format);
|
||||
op = (type == JOF_QARG)
|
||||
? JSOP_GETARG
|
||||
: (type == JOF_LOCAL)
|
||||
|
@ -1647,10 +1647,9 @@ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
}
|
||||
|
||||
uintN
|
||||
js_FramePCToLineNumber(JSContext *cx, StackFrame *fp)
|
||||
js_FramePCToLineNumber(JSContext *cx, StackFrame *fp, jsbytecode *pc)
|
||||
{
|
||||
return js_PCToLineNumber(cx, fp->script(),
|
||||
fp->hasImacropc() ? fp->imacropc() : fp->pc(cx));
|
||||
return js_PCToLineNumber(cx, fp->script(), fp->hasImacropc() ? fp->imacropc() : pc);
|
||||
}
|
||||
|
||||
uintN
|
||||
@ -1765,19 +1764,32 @@ js_GetScriptLineExtent(JSScript *script)
|
||||
return 1 + lineno - script->lineno;
|
||||
}
|
||||
|
||||
const char *
|
||||
js::CurrentScriptFileAndLineSlow(JSContext *cx, uintN *linenop)
|
||||
namespace js {
|
||||
|
||||
uintN
|
||||
CurrentLine(JSContext *cx)
|
||||
{
|
||||
StackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
||||
if (!fp) {
|
||||
return js_FramePCToLineNumber(cx, cx->fp(), cx->regs().pc);
|
||||
}
|
||||
|
||||
const char *
|
||||
CurrentScriptFileAndLineSlow(JSContext *cx, uintN *linenop)
|
||||
{
|
||||
FrameRegsIter iter(cx);
|
||||
while (!iter.done() && !iter.fp()->isScriptFrame())
|
||||
++iter;
|
||||
|
||||
if (iter.done()) {
|
||||
*linenop = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*linenop = js_FramePCToLineNumber(cx, fp);
|
||||
return fp->script()->filename;
|
||||
*linenop = js_FramePCToLineNumber(cx, iter.fp(), iter.pc());
|
||||
return iter.fp()->script()->filename;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
class DisablePrincipalsTranscoding {
|
||||
JSSecurityCallbacks *callbacks;
|
||||
JSPrincipalsTranscoder temp;
|
||||
|
@ -738,7 +738,7 @@ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
* fp->imacpc may be non-null, indicating an active imacro.
|
||||
*/
|
||||
extern uintN
|
||||
js_FramePCToLineNumber(JSContext *cx, js::StackFrame *fp);
|
||||
js_FramePCToLineNumber(JSContext *cx, js::StackFrame *fp, jsbytecode *pc);
|
||||
|
||||
extern uintN
|
||||
js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
@ -751,6 +751,9 @@ js_GetScriptLineExtent(JSScript *script);
|
||||
|
||||
namespace js {
|
||||
|
||||
extern uintN
|
||||
CurrentLine(JSContext *cx);
|
||||
|
||||
/*
|
||||
* This function returns the file and line number of the script currently
|
||||
* executing on cx. If there is no current script executing on cx (e.g., a
|
||||
|
@ -384,6 +384,14 @@ ValueToTypeChar(const Value &v)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uintN
|
||||
CurrentPCOffset(JSContext *cx)
|
||||
{
|
||||
StackFrame *fp = cx->fp();
|
||||
jsbytecode *pc = fp->hasImacropc() ? fp->imacropc() : cx->regs().pc;
|
||||
return uintN(pc - fp->script()->code);
|
||||
}
|
||||
|
||||
|
||||
/* Blacklist parameters. */
|
||||
|
||||
@ -1636,8 +1644,8 @@ TreeFragment::initialize(JSContext* cx, SlotList *globalSlots, bool speculate)
|
||||
|
||||
#ifdef DEBUG
|
||||
this->treeFileName = cx->fp()->script()->filename;
|
||||
this->treeLineNumber = js_FramePCToLineNumber(cx, cx->fp());
|
||||
this->treePCOffset = FramePCOffset(cx, cx->fp());
|
||||
this->treeLineNumber = CurrentLine(cx);
|
||||
this->treePCOffset = CurrentPCOffset(cx);
|
||||
#endif
|
||||
this->script = cx->fp()->script();
|
||||
this->gcthings.clear();
|
||||
@ -2537,8 +2545,8 @@ TraceRecorder::finishAbort(const char* reason)
|
||||
tree->treeLineNumber,
|
||||
tree->treePCOffset,
|
||||
cx->fp()->script()->filename,
|
||||
js_FramePCToLineNumber(cx, cx->fp()),
|
||||
FramePCOffset(cx, cx->fp()),
|
||||
CurrentLine(cx),
|
||||
CurrentPCOffset(cx),
|
||||
reason);
|
||||
#endif
|
||||
Backoff(traceMonitor, (jsbytecode*) fragment->root->ip, fragment->root);
|
||||
@ -4178,7 +4186,7 @@ TreevisLogExit(JSContext* cx, VMSideExit* exit)
|
||||
debug_only_printf(LC_TMTreeVis, "TREEVIS ADDEXIT EXIT=%p TYPE=%s FRAG=%p PC=%p FILE=\"%s\""
|
||||
" LINE=%d OFFS=%d", (void*)exit, getExitName(exit->exitType),
|
||||
(void*)exit->from, (void*)cx->regs().pc, cx->fp()->script()->filename,
|
||||
js_FramePCToLineNumber(cx, cx->fp()), FramePCOffset(cx, cx->fp()));
|
||||
CurrentLine(cx), CurrentPCOffset(cx));
|
||||
debug_only_print0(LC_TMTreeVis, " STACK=\"");
|
||||
for (unsigned i = 0; i < exit->numStackSlots; i++)
|
||||
debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(exit->stackTypeMap()[i]));
|
||||
@ -4532,8 +4540,7 @@ TraceRecorder::compile()
|
||||
const char* filename = cx->fp()->script()->filename;
|
||||
char* label = (char*) cx->malloc_((filename ? strlen(filename) : 7) + 16);
|
||||
if (label) {
|
||||
sprintf(label, "%s:%u", filename ? filename : "<stdin>",
|
||||
js_FramePCToLineNumber(cx, cx->fp()));
|
||||
sprintf(label, "%s:%u", filename ? filename : "<stdin>", CurrentLine(cx));
|
||||
lirbuf->printer->addrNameMap->addAddrRange(fragment, sizeof(Fragment), 0, label);
|
||||
cx->free_(label);
|
||||
}
|
||||
@ -5011,8 +5018,8 @@ TraceRecorder::closeLoop()
|
||||
debug_only_printf(LC_TMMinimal,
|
||||
"Recording completed at %s:%u@%u via closeLoop (FragID=%06u)\n",
|
||||
cx->fp()->script()->filename,
|
||||
js_FramePCToLineNumber(cx, cx->fp()),
|
||||
FramePCOffset(cx, cx->fp()),
|
||||
CurrentLine(cx),
|
||||
CurrentPCOffset(cx),
|
||||
fragment->profFragID);
|
||||
debug_only_print0(LC_TMMinimal, "\n");
|
||||
#endif
|
||||
@ -5179,8 +5186,8 @@ TraceRecorder::endLoop(VMSideExit* exit)
|
||||
debug_only_printf(LC_TMMinimal,
|
||||
"Recording completed at %s:%u@%u via endLoop (FragID=%06u)\n",
|
||||
cx->fp()->script()->filename,
|
||||
js_FramePCToLineNumber(cx, cx->fp()),
|
||||
FramePCOffset(cx, cx->fp()),
|
||||
CurrentLine(cx),
|
||||
CurrentPCOffset(cx),
|
||||
fragment->profFragID);
|
||||
debug_only_print0(LC_TMTracer, "\n");
|
||||
#endif
|
||||
@ -5744,8 +5751,7 @@ RecordTree(JSContext* cx, TraceMonitor* tm, TreeFragment* first,
|
||||
#endif
|
||||
#ifdef JS_JIT_SPEW
|
||||
debug_only_printf(LC_TMTreeVis, "TREEVIS CREATETREE ROOT=%p PC=%p FILE=\"%s\" LINE=%d OFFS=%d",
|
||||
(void*)f, f->ip, f->treeFileName, f->treeLineNumber,
|
||||
FramePCOffset(cx, cx->fp()));
|
||||
(void*)f, f->ip, f->treeFileName, f->treeLineNumber, CurrentPCOffset(cx));
|
||||
debug_only_print0(LC_TMTreeVis, " STACK=\"");
|
||||
for (unsigned i = 0; i < f->nStackTypes; i++)
|
||||
debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(f->typeMap[i]));
|
||||
@ -5867,8 +5873,7 @@ CreateBranchFragment(JSContext* cx, TraceMonitor* tm, TreeFragment* root, VMSide
|
||||
debug_only_printf(LC_TMTreeVis, "TREEVIS CREATEBRANCH ROOT=%p FRAG=%p PC=%p FILE=\"%s\""
|
||||
" LINE=%d ANCHOR=%p OFFS=%d\n",
|
||||
(void*)root, (void*)f, (void*)cx->regs().pc, cx->fp()->script()->filename,
|
||||
js_FramePCToLineNumber(cx, cx->fp()), (void*)anchor,
|
||||
FramePCOffset(cx, cx->fp()));
|
||||
CurrentLine(cx), (void*)anchor, CurrentPCOffset(cx));
|
||||
verbose_only( tm->branches = new (*tm->dataAlloc) Seq<Fragment*>(f, tm->branches); )
|
||||
|
||||
f->root = root;
|
||||
@ -5981,7 +5986,7 @@ AttemptToExtendTree(JSContext* cx, TraceMonitor* tm, VMSideExit* anchor, VMSideE
|
||||
}
|
||||
|
||||
static JS_REQUIRES_STACK bool
|
||||
ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f, uintN& inlineCallCount,
|
||||
ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f,
|
||||
VMSideExit** innermostNestedGuardp, VMSideExit** lrp);
|
||||
|
||||
static inline MonitorResult
|
||||
@ -5995,7 +6000,7 @@ RecordingIfTrue(bool b)
|
||||
* MONITOR_RECORDING, the recording has been aborted.
|
||||
*/
|
||||
JS_REQUIRES_STACK MonitorResult
|
||||
TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount)
|
||||
TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r)
|
||||
{
|
||||
TraceMonitor* tm = r->traceMonitor;
|
||||
|
||||
@ -6025,8 +6030,8 @@ TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCall
|
||||
debug_only_printf(LC_TMTracer,
|
||||
"Looking for type-compatible peer (%s:%d@%d)\n",
|
||||
cx->fp()->script()->filename,
|
||||
js_FramePCToLineNumber(cx, cx->fp()),
|
||||
FramePCOffset(cx, cx->fp()));
|
||||
CurrentLine(cx),
|
||||
CurrentPCOffset(cx));
|
||||
|
||||
// Find a matching inner tree. If none can be found, compile one.
|
||||
TreeFragment* f = r->findNestedCompatiblePeer(first);
|
||||
@ -6046,7 +6051,7 @@ TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCall
|
||||
outerScript, outerPC, outerArgc, globalSlots));
|
||||
}
|
||||
|
||||
AbortableRecordingStatus status = r->attemptTreeCall(f, inlineCallCount);
|
||||
AbortableRecordingStatus status = r->attemptTreeCall(f);
|
||||
if (status == ARECORD_CONTINUE)
|
||||
return MONITOR_RECORDING;
|
||||
if (status == ARECORD_ERROR) {
|
||||
@ -6059,15 +6064,11 @@ TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCall
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::attemptTreeCall(TreeFragment* f, uintN& inlineCallCount)
|
||||
TraceRecorder::attemptTreeCall(TreeFragment* f)
|
||||
{
|
||||
adjustCallerTypes(f);
|
||||
prepareTreeCall(f);
|
||||
|
||||
#ifdef DEBUG
|
||||
uintN oldInlineCallCount = inlineCallCount;
|
||||
#endif
|
||||
|
||||
JSContext *localCx = cx;
|
||||
TraceMonitor *localtm = traceMonitor;
|
||||
|
||||
@ -6086,7 +6087,7 @@ TraceRecorder::attemptTreeCall(TreeFragment* f, uintN& inlineCallCount)
|
||||
|
||||
VMSideExit* innermostNestedGuard = NULL;
|
||||
VMSideExit* lr;
|
||||
bool ok = ExecuteTree(cx, traceMonitor, f, inlineCallCount, &innermostNestedGuard, &lr);
|
||||
bool ok = ExecuteTree(cx, traceMonitor, f, &innermostNestedGuard, &lr);
|
||||
|
||||
/*
|
||||
* If ExecuteTree reentered the interpreter, it may have killed |this|
|
||||
@ -6120,8 +6121,6 @@ TraceRecorder::attemptTreeCall(TreeFragment* f, uintN& inlineCallCount)
|
||||
: ARECORD_ABORTED;
|
||||
}
|
||||
|
||||
JS_ASSERT(oldInlineCallCount == inlineCallCount);
|
||||
|
||||
/* Emit a call to the inner tree and continue recording the outer tree trace. */
|
||||
emitTreeCall(f, lr);
|
||||
return ARECORD_CONTINUE;
|
||||
@ -6427,7 +6426,7 @@ FindVMCompatiblePeer(JSContext* cx, JSObject* globalObj, TreeFragment* f, uintN&
|
||||
*/
|
||||
JS_ALWAYS_INLINE
|
||||
TracerState::TracerState(JSContext* cx, TraceMonitor* tm, TreeFragment* f,
|
||||
uintN& inlineCallCount, VMSideExit** innermostNestedGuardp)
|
||||
VMSideExit** innermostNestedGuardp)
|
||||
: cx(cx),
|
||||
traceMonitor(tm),
|
||||
stackBase(tm->storage->stack()),
|
||||
@ -6436,13 +6435,11 @@ TracerState::TracerState(JSContext* cx, TraceMonitor* tm, TreeFragment* f,
|
||||
callstackBase(tm->storage->callstack()),
|
||||
sor(callstackBase),
|
||||
rp(callstackBase),
|
||||
eor(callstackBase + JS_MIN(TraceNativeStorage::MAX_CALL_STACK_ENTRIES,
|
||||
StackSpace::MAX_INLINE_CALLS - inlineCallCount)),
|
||||
eor(callstackBase + TraceNativeStorage::MAX_CALL_STACK_ENTRIES),
|
||||
lastTreeExitGuard(NULL),
|
||||
lastTreeCallGuard(NULL),
|
||||
rpAtLastTreeCall(NULL),
|
||||
outermostTree(f),
|
||||
inlineCallCountp(&inlineCallCount),
|
||||
innermostNestedGuardp(innermostNestedGuardp),
|
||||
#ifdef EXECUTE_TREE_TIMER
|
||||
startTime(rdtsc()),
|
||||
@ -6469,13 +6466,6 @@ TracerState::TracerState(JSContext* cx, TraceMonitor* tm, TreeFragment* f,
|
||||
JS_ASSERT(eos == stackBase + TraceNativeStorage::MAX_NATIVE_STACK_SLOTS);
|
||||
JS_ASSERT(sp < eos);
|
||||
|
||||
/*
|
||||
* inlineCallCount has already been incremented, if being invoked from
|
||||
* EnterFrame. It is okay to have a 0-frame restriction since the JIT
|
||||
* might not need any frames.
|
||||
*/
|
||||
JS_ASSERT(inlineCallCount <= StackSpace::MAX_INLINE_CALLS);
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Cannot 0xCD-fill global frame since it may overwrite a bailed outer
|
||||
@ -6576,7 +6566,7 @@ LeaveTree(TraceMonitor *tm, TracerState&, VMSideExit *lr);
|
||||
|
||||
/* Return false if the interpreter should goto error. */
|
||||
static JS_REQUIRES_STACK bool
|
||||
ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f, uintN& inlineCallCount,
|
||||
ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f,
|
||||
VMSideExit** innermostNestedGuardp, VMSideExit **lrp)
|
||||
{
|
||||
#ifdef MOZ_TRACEVIS
|
||||
@ -6584,8 +6574,7 @@ ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f, uintN& inlineCallC
|
||||
#endif
|
||||
JS_ASSERT(f->root == f && f->code());
|
||||
|
||||
if (!ScopeChainCheck(cx, f) || !cx->stack.space().ensureEnoughSpaceToEnterTrace() ||
|
||||
inlineCallCount + f->maxCallDepth > StackSpace::MAX_INLINE_CALLS) {
|
||||
if (!ScopeChainCheck(cx, f) || !cx->stack.space().ensureEnoughSpaceToEnterTrace()) {
|
||||
*lrp = NULL;
|
||||
return true;
|
||||
}
|
||||
@ -6597,7 +6586,7 @@ ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f, uintN& inlineCallC
|
||||
f->globalObj->shape() == f->globalShape);
|
||||
|
||||
/* Initialize trace state. */
|
||||
TracerState state(cx, tm, f, inlineCallCount, innermostNestedGuardp);
|
||||
TracerState state(cx, tm, f, innermostNestedGuardp);
|
||||
double* stack = tm->storage->stack();
|
||||
double* global = tm->storage->global();
|
||||
JSObject* globalObj = f->globalObj;
|
||||
@ -6610,8 +6599,8 @@ ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f, uintN& inlineCallC
|
||||
AUDIT(traceTriggered);
|
||||
debug_only_printf(LC_TMTracer, "entering trace at %s:%u@%u, execs: %u code: %p\n",
|
||||
cx->fp()->script()->filename,
|
||||
js_FramePCToLineNumber(cx, cx->fp()),
|
||||
FramePCOffset(cx, cx->fp()),
|
||||
CurrentLine(cx),
|
||||
CurrentPCOffset(cx),
|
||||
f->execs,
|
||||
(void *) f->code());
|
||||
|
||||
@ -6655,7 +6644,7 @@ ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f, uintN& inlineCallC
|
||||
f->treeLineNumber, prefix, (uintN)iters, f->execs,
|
||||
getExitName(lr->exitType),
|
||||
fp->script()->filename,
|
||||
js_FramePCToLineNumber(cx, fp),
|
||||
CurrentLine(cx),
|
||||
js_CodeName[fp->hasImacropc() ? *fp->imacropc() : *cx->regs().pc]);
|
||||
#endif
|
||||
|
||||
@ -6845,12 +6834,11 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr)
|
||||
/* Finish initializing cx->fp() and push a new cx->fp(). */
|
||||
SynthesizeFrame(cx, *fi, callee);
|
||||
#ifdef DEBUG
|
||||
StackFrame* fp = cx->fp();
|
||||
debug_only_printf(LC_TMTracer,
|
||||
"synthesized deep frame for %s:%u@%u, slots=%d, fi=%p\n",
|
||||
fp->script()->filename,
|
||||
js_FramePCToLineNumber(cx, fp),
|
||||
FramePCOffset(cx, fp),
|
||||
cx->fp()->script()->filename,
|
||||
CurrentLine(cx),
|
||||
CurrentPCOffset(cx),
|
||||
slots,
|
||||
(void*)*callstack);
|
||||
#endif
|
||||
@ -6858,7 +6846,6 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr)
|
||||
* Keep track of the additional frames we put on the interpreter stack
|
||||
* and the native stack slots we consumed.
|
||||
*/
|
||||
++*state.inlineCallCountp;
|
||||
++callstack;
|
||||
stack += slots;
|
||||
}
|
||||
@ -6878,13 +6865,12 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr)
|
||||
|
||||
/* Reconstruct the frame. */
|
||||
SynthesizeFrame(cx, *callstack[n], callee);
|
||||
++*state.inlineCallCountp;
|
||||
#ifdef DEBUG
|
||||
StackFrame* fp = cx->fp();
|
||||
debug_only_printf(LC_TMTracer,
|
||||
"synthesized shallow frame for %s:%u@%u\n",
|
||||
fp->script()->filename, js_FramePCToLineNumber(cx, fp),
|
||||
FramePCOffset(cx, fp));
|
||||
cx->fp()->script()->filename,
|
||||
CurrentLine(cx),
|
||||
CurrentPCOffset(cx));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -6937,8 +6923,8 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr)
|
||||
"leaving trace at %s:%u@%u, op=%s, lr=%p, exitType=%s, sp=%lld, "
|
||||
"calldepth=%d, cycles=%llu\n",
|
||||
fp->script()->filename,
|
||||
js_FramePCToLineNumber(cx, fp),
|
||||
FramePCOffset(cx, fp),
|
||||
CurrentLine(cx),
|
||||
CurrentPCOffset(cx),
|
||||
js_CodeName[fp->hasImacropc() ? *fp->imacropc() : *cx->regs().pc],
|
||||
(void*)lr,
|
||||
getExitName(lr->exitType),
|
||||
@ -7035,7 +7021,7 @@ TraceRecorder::assertInsideLoop()
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK MonitorResult
|
||||
RecordLoopEdge(JSContext* cx, TraceMonitor* tm, uintN& inlineCallCount)
|
||||
RecordLoopEdge(JSContext* cx, TraceMonitor* tm)
|
||||
{
|
||||
#ifdef MOZ_TRACEVIS
|
||||
TraceVisStateObj tvso(cx, S_MONITOR);
|
||||
@ -7053,7 +7039,7 @@ RecordLoopEdge(JSContext* cx, TraceMonitor* tm, uintN& inlineCallCount)
|
||||
return MONITOR_NOT_RECORDING;
|
||||
}
|
||||
} else {
|
||||
MonitorResult r = TraceRecorder::recordLoopEdge(cx, tm->recorder, inlineCallCount);
|
||||
MonitorResult r = TraceRecorder::recordLoopEdge(cx, tm->recorder);
|
||||
JS_ASSERT((r == MONITOR_RECORDING) == (tm->recorder != NULL));
|
||||
if (r == MONITOR_RECORDING || r == MONITOR_ERROR)
|
||||
return r;
|
||||
@ -7140,8 +7126,7 @@ RecordLoopEdge(JSContext* cx, TraceMonitor* tm, uintN& inlineCallCount)
|
||||
|
||||
debug_only_printf(LC_TMTracer,
|
||||
"Looking for compat peer %d@%d, from %p (ip: %p)\n",
|
||||
js_FramePCToLineNumber(cx, cx->fp()),
|
||||
FramePCOffset(cx, cx->fp()), (void*)f, f->ip);
|
||||
CurrentLine(cx), CurrentPCOffset(cx), (void*)f, f->ip);
|
||||
|
||||
uintN count;
|
||||
TreeFragment* match = FindVMCompatiblePeer(cx, globalObj, f, count);
|
||||
@ -7164,7 +7149,7 @@ RecordLoopEdge(JSContext* cx, TraceMonitor* tm, uintN& inlineCallCount)
|
||||
VMSideExit* lr = NULL;
|
||||
VMSideExit* innermostNestedGuard = NULL;
|
||||
|
||||
if (!ExecuteTree(cx, tm, match, inlineCallCount, &innermostNestedGuard, &lr))
|
||||
if (!ExecuteTree(cx, tm, match, &innermostNestedGuard, &lr))
|
||||
return MONITOR_ERROR;
|
||||
|
||||
if (!lr) {
|
||||
@ -16711,8 +16696,7 @@ class AutoRetBlacklist
|
||||
};
|
||||
|
||||
JS_REQUIRES_STACK TracePointAction
|
||||
RecordTracePoint(JSContext* cx, TraceMonitor* tm,
|
||||
uintN& inlineCallCount, bool* blacklist, bool execAllowed)
|
||||
RecordTracePoint(JSContext* cx, TraceMonitor* tm, bool* blacklist, bool execAllowed)
|
||||
{
|
||||
StackFrame* fp = cx->fp();
|
||||
jsbytecode* pc = cx->regs().pc;
|
||||
@ -16736,8 +16720,7 @@ RecordTracePoint(JSContext* cx, TraceMonitor* tm,
|
||||
|
||||
debug_only_printf(LC_TMTracer,
|
||||
"Looking for compat peer %d@%d, from %p (ip: %p)\n",
|
||||
js_FramePCToLineNumber(cx, cx->fp()),
|
||||
FramePCOffset(cx, cx->fp()), (void*)tree, tree->ip);
|
||||
CurrentLine(cx), CurrentPCOffset(cx), (void*)tree, tree->ip);
|
||||
|
||||
if (tree->code() || tree->peer) {
|
||||
uintN count;
|
||||
@ -16753,7 +16736,7 @@ RecordTracePoint(JSContext* cx, TraceMonitor* tm,
|
||||
}
|
||||
|
||||
/* Best case - just go and execute. */
|
||||
if (!ExecuteTree(cx, tm, match, inlineCallCount, &innermostNestedGuard, &lr))
|
||||
if (!ExecuteTree(cx, tm, match, &innermostNestedGuard, &lr))
|
||||
return TPA_Error;
|
||||
|
||||
if (!lr)
|
||||
@ -16811,7 +16794,7 @@ RecordTracePoint(JSContext* cx, TraceMonitor* tm,
|
||||
JS_ASSERT(tm->recorder);
|
||||
|
||||
/* Locked and loaded with a recorder. Ask the interperter to go run some code. */
|
||||
if (!Interpret(cx, fp, inlineCallCount, JSINTERP_RECORD))
|
||||
if (!Interpret(cx, fp, JSINTERP_RECORD))
|
||||
return TPA_Error;
|
||||
|
||||
JS_ASSERT(!cx->isExceptionPending());
|
||||
@ -16853,7 +16836,7 @@ LoopProfile::reset()
|
||||
}
|
||||
|
||||
MonitorResult
|
||||
LoopProfile::profileLoopEdge(JSContext* cx, uintN& inlineCallCount)
|
||||
LoopProfile::profileLoopEdge(JSContext* cx)
|
||||
{
|
||||
if (cx->regs().pc == top) {
|
||||
debug_only_print0(LC_TMProfiler, "Profiling complete (edge)\n");
|
||||
@ -16962,13 +16945,13 @@ LoopProfile::stopProfiling(JSContext *cx)
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK TracePointAction
|
||||
MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist,
|
||||
MonitorTracePoint(JSContext *cx, bool* blacklist,
|
||||
void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits)
|
||||
{
|
||||
TraceMonitor *tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx);
|
||||
|
||||
if (!cx->profilingEnabled)
|
||||
return RecordTracePoint(cx, tm, inlineCallCount, blacklist, true);
|
||||
return RecordTracePoint(cx, tm, blacklist, true);
|
||||
|
||||
*blacklist = false;
|
||||
|
||||
@ -16998,14 +16981,13 @@ MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist,
|
||||
|
||||
if (prof->profiled) {
|
||||
if (prof->traceOK) {
|
||||
return RecordTracePoint(cx, tm, inlineCallCount, blacklist, prof->execOK);
|
||||
return RecordTracePoint(cx, tm, blacklist, prof->execOK);
|
||||
} else {
|
||||
return TPA_Nothing;
|
||||
}
|
||||
}
|
||||
|
||||
debug_only_printf(LC_TMProfiler, "Profiling at line %d\n",
|
||||
js_FramePCToLineNumber(cx, cx->fp()));
|
||||
debug_only_printf(LC_TMProfiler, "Profiling at line %d\n", CurrentLine(cx));
|
||||
|
||||
tm->profile = prof;
|
||||
|
||||
@ -17013,7 +16995,7 @@ MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist,
|
||||
JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL);
|
||||
JS_THREAD_DATA(cx)->profilingCompartment = cx->compartment;
|
||||
|
||||
if (!Interpret(cx, cx->fp(), inlineCallCount, JSINTERP_PROFILE))
|
||||
if (!Interpret(cx, cx->fp(), JSINTERP_PROFILE))
|
||||
return TPA_Error;
|
||||
|
||||
JS_ASSERT(!cx->isExceptionPending());
|
||||
@ -17060,7 +17042,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op)
|
||||
|
||||
if (!PCWithinLoop(fp, pc, *this)) {
|
||||
debug_only_printf(LC_TMProfiler, "Profiling complete (loop exit) at line %u\n",
|
||||
js_FramePCToLineNumber(cx, cx->fp()));
|
||||
CurrentLine(cx));
|
||||
tm->profile->decide(cx);
|
||||
stopProfiling(cx);
|
||||
return ProfComplete;
|
||||
@ -17081,7 +17063,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op)
|
||||
}
|
||||
|
||||
debug_only_printf(LC_TMProfiler, "Profiler: Entering inner loop at line %d\n",
|
||||
js_FramePCToLineNumber(cx, cx->fp()));
|
||||
CurrentLine(cx));
|
||||
loopStack[loopStackDepth++] = InnerLoop(fp, pc, GetLoopBottom(cx));
|
||||
}
|
||||
}
|
||||
@ -17442,13 +17424,13 @@ LoopProfile::decide(JSContext *cx)
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK MonitorResult
|
||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, InterpMode interpMode)
|
||||
MonitorLoopEdge(JSContext* cx, InterpMode interpMode)
|
||||
{
|
||||
TraceMonitor *tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx);
|
||||
if (interpMode == JSINTERP_PROFILE && tm->profile)
|
||||
return tm->profile->profileLoopEdge(cx, inlineCallCount);
|
||||
return tm->profile->profileLoopEdge(cx);
|
||||
else
|
||||
return RecordLoopEdge(cx, tm, inlineCallCount);
|
||||
return RecordLoopEdge(cx, tm);
|
||||
}
|
||||
|
||||
void
|
||||
@ -17467,10 +17449,10 @@ AbortProfiling(JSContext *cx)
|
||||
#else /* JS_METHODJIT */
|
||||
|
||||
JS_REQUIRES_STACK MonitorResult
|
||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, InterpMode interpMode)
|
||||
MonitorLoopEdge(JSContext* cx, InterpMode interpMode)
|
||||
{
|
||||
TraceMonitor *tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx);
|
||||
return RecordLoopEdge(cx, tm, inlineCallCount);
|
||||
return RecordLoopEdge(cx, tm);
|
||||
}
|
||||
|
||||
#endif /* JS_METHODJIT */
|
||||
|
@ -794,7 +794,7 @@ public:
|
||||
inline uintN count(OpKind kind) { return allOps[kind]; }
|
||||
|
||||
/* Called for every back edge being profiled. */
|
||||
MonitorResult profileLoopEdge(JSContext* cx, uintN& inlineCallCount);
|
||||
MonitorResult profileLoopEdge(JSContext* cx);
|
||||
|
||||
/* Called for every instruction being profiled. */
|
||||
ProfileAction profileOperation(JSContext *cx, JSOp op);
|
||||
@ -1539,11 +1539,9 @@ class TraceRecorder
|
||||
JS_REQUIRES_STACK void determineGlobalTypes(JSValueType* typeMap);
|
||||
JS_REQUIRES_STACK VMSideExit* downSnapshot(FrameInfo* downFrame);
|
||||
JS_REQUIRES_STACK TreeFragment* findNestedCompatiblePeer(TreeFragment* f);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus attemptTreeCall(TreeFragment* inner,
|
||||
uintN& inlineCallCount);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus attemptTreeCall(TreeFragment* inner);
|
||||
|
||||
static JS_REQUIRES_STACK MonitorResult recordLoopEdge(JSContext* cx, TraceRecorder* r,
|
||||
uintN& inlineCallCount);
|
||||
static JS_REQUIRES_STACK MonitorResult recordLoopEdge(JSContext* cx, TraceRecorder* r);
|
||||
|
||||
/* Allocators associated with this recording session. */
|
||||
VMAllocator& tempAlloc() const { return *traceMonitor->tempAlloc; }
|
||||
@ -1597,9 +1595,8 @@ class TraceRecorder
|
||||
friend class SlotMap;
|
||||
friend class DefaultSlotMap;
|
||||
friend class DetermineTypesVisitor;
|
||||
friend MonitorResult RecordLoopEdge(JSContext*, TraceMonitor*, uintN&);
|
||||
friend TracePointAction RecordTracePoint(JSContext*, TraceMonitor*, uintN &inlineCallCount,
|
||||
bool *blacklist);
|
||||
friend MonitorResult RecordLoopEdge(JSContext*, TraceMonitor*);
|
||||
friend TracePointAction RecordTracePoint(JSContext*, TraceMonitor*, bool *blacklist);
|
||||
friend AbortResult AbortRecording(JSContext*, const char*);
|
||||
friend class BoxArg;
|
||||
friend void TraceMonitor::sweep(JSContext *cx);
|
||||
@ -1685,14 +1682,14 @@ class TraceRecorder
|
||||
#define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b))
|
||||
|
||||
extern JS_REQUIRES_STACK MonitorResult
|
||||
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, InterpMode interpMode);
|
||||
MonitorLoopEdge(JSContext* cx, InterpMode interpMode);
|
||||
|
||||
extern JS_REQUIRES_STACK TracePointAction
|
||||
RecordTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist);
|
||||
RecordTracePoint(JSContext*, bool* blacklist);
|
||||
|
||||
extern JS_REQUIRES_STACK TracePointAction
|
||||
MonitorTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist,
|
||||
void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits);
|
||||
MonitorTracePoint(JSContext*, bool* blacklist, void** traceData, uintN *traceEpoch,
|
||||
uint32 *loopCounter, uint32 hits);
|
||||
|
||||
extern JS_REQUIRES_STACK TraceRecorder::AbortResult
|
||||
AbortRecording(JSContext* cx, const char* reason);
|
||||
|
@ -1742,11 +1742,10 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
||||
filename = NULL;
|
||||
lineno = 1;
|
||||
if (!i.done()) {
|
||||
StackFrame *fp = i.fp();
|
||||
op = (JSOp) *i.pc();
|
||||
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
|
||||
filename = fp->script()->filename;
|
||||
lineno = js_FramePCToLineNumber(cx, fp);
|
||||
filename = i.fp()->script()->filename;
|
||||
lineno = js_FramePCToLineNumber(cx, i.fp(), i.pc());
|
||||
for (endp = srcp + srclen; srcp < endp; srcp++) {
|
||||
if (*srcp == '\n')
|
||||
--lineno;
|
||||
|
@ -220,8 +220,7 @@ stubs::HitStackQuota(VMFrame &f)
|
||||
/* Include space to push another frame. */
|
||||
uintN nvals = f.fp()->script()->nslots + VALUES_PER_STACK_FRAME;
|
||||
JS_ASSERT(f.regs.sp == f.fp()->base());
|
||||
StackSpace &space = f.cx->stack.space();
|
||||
if (space.bumpLimitWithinQuota(NULL, f.entryfp, f.regs.sp, nvals, &f.stackLimit))
|
||||
if (f.cx->stack.space().tryBumpLimit(NULL, f.regs.sp, nvals, &f.stackLimit))
|
||||
return;
|
||||
|
||||
/* Remove the current partially-constructed frame before throwing. */
|
||||
@ -258,7 +257,7 @@ stubs::FixupArity(VMFrame &f, uint32 nactual)
|
||||
/* Reserve enough space for a callee frame. */
|
||||
StackFrame *newfp = cx->stack.getInlineFrameWithinLimit(cx, (Value*) oldfp, nactual,
|
||||
fun, fun->script(), &flags,
|
||||
f.entryfp, &f.stackLimit);
|
||||
&f.stackLimit);
|
||||
if (!newfp) {
|
||||
/*
|
||||
* The PC is not coherent with the current frame, so fix it up for
|
||||
@ -343,7 +342,7 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint
|
||||
/* Get pointer to new frame/slots, prepare arguments. */
|
||||
StackFrame *newfp = cx->stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc,
|
||||
newfun, newscript, &flags,
|
||||
f.entryfp, &f.stackLimit);
|
||||
&f.stackLimit);
|
||||
if (JS_UNLIKELY(!newfp))
|
||||
return false;
|
||||
|
||||
@ -696,7 +695,7 @@ PartialInterpret(VMFrame &f)
|
||||
#endif
|
||||
|
||||
JSBool ok = JS_TRUE;
|
||||
ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);
|
||||
ok = Interpret(cx, fp, JSINTERP_SAFEPOINT);
|
||||
|
||||
return ok;
|
||||
}
|
||||
@ -946,7 +945,6 @@ RunTracer(VMFrame &f)
|
||||
entryFrame->returnValue();
|
||||
|
||||
bool blacklist;
|
||||
uintN inlineCallCount = 0;
|
||||
void **traceData;
|
||||
uintN *traceEpoch;
|
||||
uint32 *loopCounter;
|
||||
@ -963,7 +961,7 @@ RunTracer(VMFrame &f)
|
||||
loopCounter = NULL;
|
||||
hits = 1;
|
||||
#endif
|
||||
tpa = MonitorTracePoint(f.cx, inlineCallCount, &blacklist, traceData, traceEpoch,
|
||||
tpa = MonitorTracePoint(f.cx, &blacklist, traceData, traceEpoch,
|
||||
loopCounter, hits);
|
||||
JS_ASSERT(!TRACE_RECORDER(cx));
|
||||
|
||||
|
@ -1035,42 +1035,12 @@ ic::NativeNew(VMFrame &f, CallICInfo *ic)
|
||||
stubs::SlowNew(f, ic->frameSize.staticArgc());
|
||||
}
|
||||
|
||||
static const unsigned MANY_ARGS = 1024;
|
||||
|
||||
static bool
|
||||
BumpStackFull(VMFrame &f, uintN inc)
|
||||
{
|
||||
/* If we are not passing many args, treat this as a normal call. */
|
||||
if (inc < MANY_ARGS) {
|
||||
if (f.regs.sp + inc < f.stackLimit)
|
||||
return true;
|
||||
StackSpace &space = f.cx->stack.space();
|
||||
return space.bumpLimitWithinQuota(f.cx, f.entryfp, f.regs.sp, inc, &f.stackLimit);
|
||||
}
|
||||
|
||||
/*
|
||||
* The purpose of f.stackLimit is to catch over-recursion based on
|
||||
* assumptions about the average frame size. 'apply' with a large number of
|
||||
* arguments breaks these assumptions and can result in premature "out of
|
||||
* script quota" errors. Normally, apply will go through js::Invoke, which
|
||||
* effectively starts a fresh stackLimit. Here, we bump f.stackLimit,
|
||||
* if necessary, to allow for this 'apply' call, and a reasonable number of
|
||||
* subsequent calls, to succeed without hitting the stackLimit. In theory,
|
||||
* this a recursive chain containing apply to circumvent the stackLimit.
|
||||
* However, since each apply call must consume at least MANY_ARGS slots,
|
||||
* this sequence will quickly reach the end of the stack and OOM.
|
||||
*/
|
||||
StackSpace &space = f.cx->stack.space();
|
||||
return space.bumpLimit(f.cx, f.entryfp, f.regs.sp, inc, &f.stackLimit);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
BumpStack(VMFrame &f, uintN inc)
|
||||
{
|
||||
/* Fast path BumpStackFull. */
|
||||
if (inc < MANY_ARGS && f.regs.sp + inc < f.stackLimit)
|
||||
if (f.regs.sp + inc < f.stackLimit)
|
||||
return true;
|
||||
return BumpStackFull(f, inc);
|
||||
return f.cx->stack.space().tryBumpLimit(f.cx, f.regs.sp, inc, &f.stackLimit);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -179,8 +179,7 @@ class PICStubCompiler : public BaseCompiler
|
||||
void spew(const char *event, const char *op) {
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
JaegerSpew(JSpew_PICs, "%s %s: %s (%s: %d)\n",
|
||||
type, event, op, script->filename,
|
||||
js_FramePCToLineNumber(cx, f.fp()));
|
||||
type, event, op, script->filename, CurrentLine(cx));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@ -2055,8 +2054,7 @@ BaseIC::spew(JSContext *cx, const char *event, const char *message)
|
||||
{
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
JaegerSpew(JSpew_PICs, "%s %s: %s (%s: %d)\n",
|
||||
js_CodeName[op], event, message, cx->fp()->script()->filename,
|
||||
js_FramePCToLineNumber(cx, cx->fp()));
|
||||
js_CodeName[op], event, message, cx->fp()->script()->filename, CurrentLine(cx));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2240,7 +2238,7 @@ GetElementIC::attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid i
|
||||
char *chars = DeflateString(cx, v.toString()->getChars(cx), v.toString()->length());
|
||||
JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom 0x%x (\"%s\") shape 0x%x (%s: %d)\n",
|
||||
js_CodeName[op], cs.executableAddress(), id, chars, holder->shape(),
|
||||
cx->fp()->script()->filename, js_FramePCToLineNumber(cx, cx->fp()));
|
||||
cx->fp()->script()->filename, CurrentLine(cx));
|
||||
cx->free_(chars);
|
||||
#endif
|
||||
|
||||
|
@ -429,7 +429,7 @@ StackFrame::initEvalFrame(JSContext *cx, JSScript *script, StackFrame *prev, uin
|
||||
|
||||
scopeChain_ = &prev->scopeChain();
|
||||
prev_ = prev;
|
||||
prevpc_ = prev->pc(cx);
|
||||
prevpc_ = prev->pcQuadratic(cx);
|
||||
JS_ASSERT(!hasImacropc());
|
||||
JS_ASSERT(!hasHookData());
|
||||
setAnnotation(prev->annotation());
|
||||
@ -767,7 +767,7 @@ StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
|
||||
return true;
|
||||
#else
|
||||
if (end_ - from < nvals) {
|
||||
js_ReportOutOfScriptQuota(maybecx);
|
||||
js_ReportOverRecursed(maybecx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -777,24 +777,22 @@ StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
|
||||
inline Value *
|
||||
StackSpace::getStackLimit(JSContext *cx)
|
||||
{
|
||||
Value *limit;
|
||||
#ifdef XP_WIN
|
||||
limit = commitEnd_;
|
||||
#else
|
||||
limit = end_;
|
||||
#endif
|
||||
|
||||
/* See getStackLimit comment in Stack.h. */
|
||||
FrameRegs ®s = cx->regs();
|
||||
uintN minSpace = regs.fp()->numSlots() + VALUES_PER_STACK_FRAME;
|
||||
Value *sp = regs.sp;
|
||||
Value *required = sp + minSpace;
|
||||
Value *desired = sp + STACK_QUOTA;
|
||||
#ifdef XP_WIN
|
||||
if (required <= commitEnd_)
|
||||
return Min(commitEnd_, desired);
|
||||
if (!bumpCommit(cx, sp, minSpace))
|
||||
if (regs.sp + minSpace > limit) {
|
||||
js_ReportOverRecursed(cx);
|
||||
return NULL;
|
||||
JS_ASSERT(commitEnd_ >= required);
|
||||
return commitEnd_;
|
||||
#else
|
||||
if (required <= end_)
|
||||
return Min(end_, desired);
|
||||
js_ReportOutOfScriptQuota(cx);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
return limit;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -819,10 +817,9 @@ struct OOMCheck
|
||||
|
||||
struct LimitCheck
|
||||
{
|
||||
StackFrame *base;
|
||||
Value **limit;
|
||||
|
||||
LimitCheck(StackFrame *base, Value **limit) : base(base), limit(limit) {}
|
||||
LimitCheck(Value **limit) : limit(limit) {}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
operator()(JSContext *cx, StackSpace &space, Value *from, uintN nvals)
|
||||
@ -836,7 +833,7 @@ struct LimitCheck
|
||||
JS_ASSERT(from < *limit);
|
||||
if (*limit - from >= ptrdiff_t(nvals))
|
||||
return true;
|
||||
return space.bumpLimitWithinQuota(cx, base, from, nvals, limit);
|
||||
return space.tryBumpLimit(cx, from, nvals, limit);
|
||||
}
|
||||
};
|
||||
|
||||
@ -896,12 +893,12 @@ ContextStack::getInlineFrame(JSContext *cx, Value *sp, uintN nactual,
|
||||
JS_ALWAYS_INLINE StackFrame *
|
||||
ContextStack::getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual,
|
||||
JSFunction *fun, JSScript *script, uint32 *flags,
|
||||
StackFrame *fp, Value **limit) const
|
||||
Value **limit) const
|
||||
{
|
||||
JS_ASSERT(isCurrentAndActive());
|
||||
JS_ASSERT(cx->regs().sp == sp);
|
||||
|
||||
return getCallFrame(cx, sp, nactual, fun, script, flags, detail::LimitCheck(fp, limit));
|
||||
return getCallFrame(cx, sp, nactual, fun, script, flags, detail::LimitCheck(limit));
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE void
|
||||
@ -1058,39 +1055,6 @@ ContextStack::findFrameAtLevel(uintN targetLevel) const
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
inline
|
||||
FrameRegsIter::FrameRegsIter(JSContext *cx)
|
||||
: cx_(cx)
|
||||
{
|
||||
seg_ = cx->stack.currentSegment();
|
||||
if (JS_UNLIKELY(!seg_ || !seg_->isActive())) {
|
||||
initSlow();
|
||||
return;
|
||||
}
|
||||
fp_ = cx->fp();
|
||||
sp_ = cx->regs().sp;
|
||||
pc_ = cx->regs().pc;
|
||||
return;
|
||||
}
|
||||
|
||||
inline FrameRegsIter &
|
||||
FrameRegsIter::operator++()
|
||||
{
|
||||
StackFrame *oldfp = fp_;
|
||||
fp_ = fp_->prev();
|
||||
if (!fp_)
|
||||
return *this;
|
||||
|
||||
if (JS_UNLIKELY(oldfp == seg_->initialFrame())) {
|
||||
incSlow(oldfp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pc_ = oldfp->prevpc();
|
||||
sp_ = oldfp->formalArgsEnd();
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo
|
||||
|
@ -90,17 +90,19 @@ StackFrame::prevpcSlow()
|
||||
}
|
||||
|
||||
jsbytecode *
|
||||
StackFrame::pc(JSContext *cx, StackFrame *next)
|
||||
StackFrame::pcQuadratic(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT_IF(next, next->prev() == this);
|
||||
|
||||
StackSegment &seg = cx->stack.space().containingSegment(this);
|
||||
FrameRegs ®s = seg.currentRegs();
|
||||
|
||||
/*
|
||||
* This isn't just an optimization; seg->computeNextFrame(fp) is only
|
||||
* defined if fp != seg->currentFrame.
|
||||
*/
|
||||
if (regs.fp() == this)
|
||||
return regs.pc;
|
||||
if (!next)
|
||||
next = seg.computeNextFrame(this);
|
||||
return next->prevpc();
|
||||
|
||||
return seg.computeNextFrame(this)->prevpc();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -299,7 +301,7 @@ JS_FRIEND_API(bool)
|
||||
StackSpace::bumpCommit(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
|
||||
{
|
||||
if (end_ - from < nvals) {
|
||||
js_ReportOutOfScriptQuota(maybecx);
|
||||
js_ReportOverRecursed(maybecx);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -317,7 +319,7 @@ StackSpace::bumpCommit(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
|
||||
int32 size = static_cast<int32>(newCommit - commitEnd_) * sizeof(Value);
|
||||
|
||||
if (!VirtualAlloc(commitEnd_, size, MEM_COMMIT, PAGE_READWRITE)) {
|
||||
js_ReportOutOfScriptQuota(maybecx);
|
||||
js_ReportOverRecursed(maybecx);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -327,44 +329,15 @@ StackSpace::bumpCommit(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
|
||||
#endif
|
||||
|
||||
bool
|
||||
StackSpace::bumpLimitWithinQuota(JSContext *maybecx, StackFrame *fp, Value *sp,
|
||||
uintN nvals, Value **limit) const
|
||||
StackSpace::tryBumpLimit(JSContext *maybecx, Value *from, uintN nvals, Value **limit)
|
||||
{
|
||||
JS_ASSERT(sp >= firstUnused());
|
||||
JS_ASSERT(sp + nvals >= *limit);
|
||||
#ifdef XP_WIN
|
||||
Value *quotaEnd = (Value *)fp + STACK_QUOTA;
|
||||
if (sp + nvals < quotaEnd) {
|
||||
if (!ensureSpace(NULL, sp, nvals))
|
||||
goto fail;
|
||||
*limit = Min(quotaEnd, commitEnd_);
|
||||
return true;
|
||||
}
|
||||
fail:
|
||||
#endif
|
||||
js_ReportOverRecursed(maybecx);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
StackSpace::bumpLimit(JSContext *cx, StackFrame *fp, Value *sp,
|
||||
uintN nvals, Value **limit) const
|
||||
{
|
||||
JS_ASSERT(*limit > base_);
|
||||
JS_ASSERT(sp < *limit);
|
||||
|
||||
/*
|
||||
* Ideally, we would only ensure space for 'nvals', not 'nvals + remain',
|
||||
* since this is ~500K. However, this whole call should be a rare case: some
|
||||
* script is passing a obscene number of args to 'apply' and we are just
|
||||
* trying to keep the stack limit heuristic from breaking the script.
|
||||
*/
|
||||
Value *quota = (Value *)fp + STACK_QUOTA;
|
||||
uintN remain = quota - sp;
|
||||
uintN inc = nvals + remain;
|
||||
if (!ensureSpace(NULL, sp, inc))
|
||||
if (!ensureSpace(maybecx, from, nvals))
|
||||
return false;
|
||||
*limit = sp + inc;
|
||||
#ifdef XP_WIN
|
||||
*limit = commitEnd_;
|
||||
#else
|
||||
*limit = end_;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -664,31 +637,44 @@ ContextStack::notifyIfNoCodeRunning()
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
FrameRegsIter::initSlow()
|
||||
FrameRegsIter::FrameRegsIter(JSContext *cx)
|
||||
: cx_(cx)
|
||||
{
|
||||
LeaveTrace(cx);
|
||||
seg_ = cx->stack.currentSegment();
|
||||
if (!seg_) {
|
||||
fp_ = NULL;
|
||||
sp_ = NULL;
|
||||
pc_ = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
JS_ASSERT(seg_->isSuspended());
|
||||
fp_ = seg_->suspendedFrame();
|
||||
sp_ = seg_->suspendedRegs().sp;
|
||||
pc_ = seg_->suspendedRegs().pc;
|
||||
if (!seg_->isActive()) {
|
||||
JS_ASSERT(seg_->isSuspended());
|
||||
fp_ = seg_->suspendedFrame();
|
||||
sp_ = seg_->suspendedRegs().sp;
|
||||
pc_ = seg_->suspendedRegs().pc;
|
||||
return;
|
||||
}
|
||||
fp_ = cx->fp();
|
||||
sp_ = cx->regs().sp;
|
||||
pc_ = cx->regs().pc;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Using the invariant described in the js::StackSegment comment, we know that,
|
||||
* when a pair of prev-linked stack frames are in the same segment, the
|
||||
* first frame's address is the top of the prev-frame's stack, modulo missing
|
||||
* arguments.
|
||||
*/
|
||||
void
|
||||
FrameRegsIter::incSlow(StackFrame *oldfp)
|
||||
FrameRegsIter &
|
||||
FrameRegsIter::operator++()
|
||||
{
|
||||
StackFrame *oldfp = fp_;
|
||||
fp_ = fp_->prev();
|
||||
if (!fp_)
|
||||
return *this;
|
||||
|
||||
if (oldfp != seg_->initialFrame()) {
|
||||
pc_ = oldfp->prevpc();
|
||||
sp_ = oldfp->formalArgsEnd();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JS_ASSERT(oldfp == seg_->initialFrame());
|
||||
JS_ASSERT(fp_ == oldfp->prev());
|
||||
|
||||
@ -714,6 +700,13 @@ FrameRegsIter::incSlow(StackFrame *oldfp)
|
||||
f = f->prev();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameRegsIter::operator==(const FrameRegsIter &rhs) const
|
||||
{
|
||||
return done() == rhs.done() && (done() || fp_ == rhs.fp_);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -428,9 +428,20 @@ class StackFrame
|
||||
|
||||
/*
|
||||
* Get the frame's current bytecode, assuming |this| is in |cx|.
|
||||
* next is frame whose prev == this, NULL if not known or if this == cx->fp().
|
||||
*
|
||||
* Beware, as the name implies, pcQuadratic can lead to quadratic behavior
|
||||
* in loops such as:
|
||||
*
|
||||
* for ( ...; fp; fp = fp->prev())
|
||||
* ... fp->pcQuadratic(cx);
|
||||
*
|
||||
* For such situations, prefer FrameRegsIter; its amortized O(1).
|
||||
*
|
||||
* When I get to the bottom I go back to the top of the stack
|
||||
* Where I stop and I turn and I go right back
|
||||
* Till I get to the bottom and I see you again...
|
||||
*/
|
||||
jsbytecode *pc(JSContext *cx, StackFrame *next = NULL);
|
||||
jsbytecode *pcQuadratic(JSContext *cx);
|
||||
|
||||
jsbytecode *prevpc() {
|
||||
if (flags_ & HAS_PREVPC)
|
||||
@ -1095,54 +1106,21 @@ class StackSpace
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If we let infinite recursion go until it hit the end of the contiguous
|
||||
* stack, it would take a long time. As a heuristic, we kill scripts which
|
||||
* go deeper than MAX_INLINE_CALLS. Note: this heuristic only applies to a
|
||||
* single activation of the VM. If a script reenters, the call count gets
|
||||
* reset. This is ok because we will quickly hit the C recursion limit.
|
||||
*/
|
||||
static const size_t MAX_INLINE_CALLS = 3000;
|
||||
|
||||
/*
|
||||
* SunSpider and v8bench have roughly an average of 9 slots per script. Our
|
||||
* heuristic for a quick over-recursion check uses a generous slot count
|
||||
* based on this estimate. We take this frame size and multiply it by the
|
||||
* old recursion limit from the interpreter. Worst case, if an average size
|
||||
* script (<=9 slots) over recurses, it'll effectively be the same as having
|
||||
* increased the old inline call count to <= 5,000.
|
||||
*/
|
||||
static const size_t STACK_QUOTA = MAX_INLINE_CALLS * (VALUES_PER_STACK_FRAME + 18);
|
||||
|
||||
/*
|
||||
* In the mjit, we'd like to collapse two "overflow" checks into one:
|
||||
* - the MAX_INLINE_CALLS check (see above comment)
|
||||
* - the stack OOM check (or, on Windows, the commit/OOM check) This
|
||||
* function produces a 'limit' pointer that satisfies both these checks.
|
||||
* (The STACK_QUOTA comment explains how this limit simulates checking
|
||||
* MAX_INLINE_CALLS.) This limit is guaranteed to have at least enough space
|
||||
* for cx->fp()->nslots() plus an extra stack frame (which is the min
|
||||
* requirement for entering mjit code) or else an error is reported and NULL
|
||||
* is returned. When the stack grows past the returned limit, the script may
|
||||
* still be within quota, but more memory needs to be committed. This is
|
||||
* handled by bumpLimitWithinQuota.
|
||||
* Return a limit against which jit code can check for. This limit is not
|
||||
* necessarily the end of the stack since we lazily commit stack memory on
|
||||
* some platforms. Thus, when the stack limit is exceeded, the caller should
|
||||
* use tryBumpLimit to attempt to increase the stack limit by committing
|
||||
* more memory. If the stack is truly exhausted, tryBumpLimit will report an
|
||||
* error and return NULL.
|
||||
*
|
||||
* An invariant of the methodjit is that there is always space to push a
|
||||
* frame on top of the current frame's expression stack (which can be at
|
||||
* most script->nslots deep). getStackLimit ensures that the returned limit
|
||||
* does indeed have this required space and reports an error and returns
|
||||
* NULL if this reserve space cannot be allocated.
|
||||
*/
|
||||
inline Value *getStackLimit(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Try to bump the limit, staying within |base + STACK_QUOTA|, by
|
||||
* committing more pages of the contiguous stack.
|
||||
* base: the frame on which execution started
|
||||
* from: the current top of the stack
|
||||
* nvals: requested space above 'from'
|
||||
* *limit: receives bumped new limit
|
||||
*/
|
||||
bool bumpLimitWithinQuota(JSContext *maybecx, StackFrame *base, Value *from, uintN nvals, Value **limit) const;
|
||||
|
||||
/*
|
||||
* Raise the given limit without considering quota.
|
||||
* See comment in BumpStackFull.
|
||||
*/
|
||||
bool bumpLimit(JSContext *cx, StackFrame *base, Value *from, uintN nvals, Value **limit) const;
|
||||
bool tryBumpLimit(JSContext *maybecx, Value *from, uintN nvals, Value **limit);
|
||||
|
||||
/* Called during GC: mark segments, frames, and slots under firstUnused. */
|
||||
void mark(JSTracer *trc);
|
||||
@ -1267,7 +1245,7 @@ class ContextStack
|
||||
|
||||
/*
|
||||
* For the five sets of stack operations below:
|
||||
* - The boolean-valued functions call js_ReportOutOfScriptQuota on OOM.
|
||||
* - The boolean-valued functions call js_ReportOverRecursed on OOM.
|
||||
* - The "get*Frame" functions do not change any global state, they just
|
||||
* check OOM and return pointers to an uninitialized frame with the
|
||||
* requested missing arguments/slots. Only once the "push*Frame"
|
||||
@ -1322,7 +1300,7 @@ class ContextStack
|
||||
inline StackFrame *
|
||||
getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual,
|
||||
JSFunction *fun, JSScript *script, uint32 *flags,
|
||||
StackFrame *base, Value **limit) const;
|
||||
Value **limit) const;
|
||||
inline void pushInlineFrame(JSScript *script, StackFrame *fp, FrameRegs ®s);
|
||||
inline void popInlineFrame();
|
||||
|
||||
@ -1424,10 +1402,12 @@ class FrameRegsIter
|
||||
void incSlow(StackFrame *oldfp);
|
||||
|
||||
public:
|
||||
inline FrameRegsIter(JSContext *cx);
|
||||
FrameRegsIter(JSContext *cx);
|
||||
|
||||
bool done() const { return fp_ == NULL; }
|
||||
inline FrameRegsIter &operator++();
|
||||
FrameRegsIter &operator++();
|
||||
bool operator==(const FrameRegsIter &rhs) const;
|
||||
bool operator!=(const FrameRegsIter &rhs) const { return !(*this == rhs); }
|
||||
|
||||
StackFrame *fp() const { return fp_; }
|
||||
Value *sp() const { return sp_; }
|
||||
|
Loading…
Reference in New Issue
Block a user