--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -245,17 +245,18 @@ public:
}
LInsp ins1(LOpcode v, LInsp s0)
{
switch (v) {
case LIR_fneg:
if (isPromoteInt(s0)) {
LIns* result = out->ins1(LIR_neg, demote(out, s0));
- out->insGuard(LIR_xt, out->ins1(LIR_ov, result), recorder.snapshot());
+ out->insGuard(LIR_xt, out->ins1(LIR_ov, result),
+ recorder.snapshot(OVERFLOW_EXIT));
return out->ins1(LIR_i2f, result);
}
break;
default:;
}
return out->ins1(v, s0);
}
@@ -291,17 +292,18 @@ public:
value range of int32 */
if (isPromoteInt(s0) && isPromoteInt(s1)) {
// demote fop to op
v = (LOpcode)((int)v & ~LIR64);
LIns* d0;
LIns* d1;
LIns* result = out->ins2(v, d0 = demote(out, s0), d1 = demote(out, s1));
if (!overflowSafe(d0) || !overflowSafe(d1))
- out->insGuard(LIR_xt, out->ins1(LIR_ov, result), recorder.snapshot());
+ out->insGuard(LIR_xt, out->ins1(LIR_ov, result),
+ recorder.snapshot(OVERFLOW_EXIT));
return out->ins1(LIR_i2f, result);
}
} else if (v == LIR_or &&
s0->isop(LIR_lsh) && isconst(s0->oprnd2(), 16) &&
s1->isop(LIR_and) && isconst(s1->oprnd2(), 0xffff)) {
LIns* msw = s0->oprnd1();
LIns* lsw = s1->oprnd1();
LIns* x;
@@ -969,51 +971,53 @@ js_IsLoopExit(JSContext* cx, JSScript* s
return GET_JUMP_OFFSET(pc) < 0;
default:;
}
return false;
}
SideExit*
-TraceRecorder::snapshot()
-{
+TraceRecorder::snapshot(ExitType exitType)
+{
+ if (exitType == BRANCH_EXIT && js_IsLoopExit(cx, cx->fp->script, cx->fp->regs->pc))
+ exitType = LOOP_EXIT;
/* generate the entry map and stash it in the trace */
unsigned stackSlots = nativeStackSlots(callDepth, cx->fp, *cx->fp->regs);
trackNativeStackUse(stackSlots);
/* reserve space for the type map */
LIns* data = lir_buf_writer->skip((stackSlots + treeInfo->ngslots) * sizeof(uint8));
/* setup side exit structure */
memset(&exit, 0, sizeof(exit));
exit.from = fragment;
exit.calldepth = getCallDepth();
exit.ip_adj = cx->fp->regs->pc - (jsbytecode*)fragment->root->ip;
exit.sp_adj = ((cx->fp->regs->sp - StackBase(cx->fp)) - treeInfo->entryStackDepth)
* sizeof(double);
exit.rp_adj = exit.calldepth * sizeof(void*);
- exit.loopExit = js_IsLoopExit(cx, cx->fp->script, cx->fp->regs->pc);
+ exit.exitType = exitType;
uint8* m = exit.typeMap = (uint8 *)data->payload();
/* Determine the type of a store by looking at the current type of the actual value the
interpreter is using. For numbers we have to check what kind of store we used last
(integer or double) to figure out what the side exit show reflect in its typemap. */
FORALL_SLOTS(cx, treeInfo->ngslots, treeInfo->gslots, callDepth,
LIns* i = get(vp);
*m++ = isNumber(*vp)
? (isPromoteInt(i) ? JSVAL_INT : JSVAL_DOUBLE)
: JSVAL_TAG(*vp);
);
return &exit;
}
LIns*
-TraceRecorder::guard(bool expected, LIns* cond)
+TraceRecorder::guard(bool expected, LIns* cond, ExitType exitType)
{
return lir->insGuard(expected ? LIR_xf : LIR_xt,
cond,
- snapshot());
+ snapshot(exitType));
}
bool
TraceRecorder::checkType(jsval& v, uint8& t)
{
if (t == TYPEMAP_TYPE_ANY) /* ignore unused slots */
return true;
if (t == JSVAL_INT) { /* initially all whole numbers cause the slot to be demoted */
@@ -1086,17 +1090,17 @@ TraceRecorder::isLoopHeader(JSContext* c
void
TraceRecorder::closeLoop(Fragmento* fragmento)
{
if (!verifyTypeStability(treeInfo->typeMap)) {
AUDIT(unstableLoopVariable);
debug_only(printf("Trace rejected: unstable loop variables.\n");)
return;
}
- SideExit *exit = snapshot();
+ SideExit *exit = snapshot(LOOP_EXIT);
exit->target = fragment->root;
if (fragment == fragment->root) {
fragment->lastIns = lir->insGuard(LIR_loop, lir->insImm(1), exit);
} else {
fragment->lastIns = lir->insGuard(LIR_x, lir->insImm(1), exit);
}
compile(fragmento->assm(), fragment);
if (anchor) {
@@ -1360,21 +1364,31 @@ js_LoopEdge(JSContext* cx, jsbytecode* o
return false;
}
GuardRecord* lr = js_ExecuteTree(cx, f);
if (!lr) /* did the tree actually execute? */
return false;
- /* if the side exit terminates the loop, don't try to attach a trace here */
- if (lr->exit->loopExit)
+ switch (lr->exit->exitType) {
+ case BRANCH_EXIT:
+ /* if its a branch, try to extend the tree */
+ return js_AttemptToExtendTree(cx, lr, f);
+ case LOOP_EXIT:
+ /* if this exits the loop, resume interpretation */
return false;
-
- return js_AttemptToExtendTree(cx, lr, f);
+ case OVERFLOW_EXIT:
+ /* a speculation failed, we should probably de-speculate */
+ return false;
+ default:
+ JS_ASSERT(lr->exit->exitType == nanojit::OOM_EXIT);
+ /* we ran out of heap, exit for now and re-enter once the GC ran */
+ return false;
+ }
}
void
js_AbortRecording(JSContext* cx, jsbytecode* abortpc, const char* reason)
{
AUDIT(recorderAborted);
debug_only(if (!abortpc) abortpc = cx->fp->regs->pc;
printf("Abort recording (line %d, pc %d): %s.\n",
@@ -1835,17 +1849,18 @@ TraceRecorder::native_get(LIns* obj_ins,
}
bool
TraceRecorder::box_jsval(jsval v, LIns*& v_ins)
{
if (isNumber(v)) {
LIns* args[] = { v_ins, cx_ins };
v_ins = lir->insCall(F_BoxDouble, args);
- guard(false, lir->ins2(LIR_eq, v_ins, lir->insImmPtr((void*)JSVAL_ERROR_COOKIE)));
+ guard(false, lir->ins2(LIR_eq, v_ins, lir->insImmPtr((void*)JSVAL_ERROR_COOKIE)),
+ OOM_EXIT);
return true;
}
switch (JSVAL_TAG(v)) {
case JSVAL_BOOLEAN:
v_ins = lir->ins2i(LIR_or, lir->ins2i(LIR_lsh, v_ins, JSVAL_TAGBITS), JSVAL_BOOLEAN);
return true;
}
return false;
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -145,17 +145,18 @@ class TraceRecorder {
bool isGlobal(jsval* p) const;
ptrdiff_t nativeStackOffset(jsval* p) const;
ptrdiff_t nativeGlobalOffset(jsval* p) const;
void import(nanojit::LIns* base, ptrdiff_t offset, jsval* p, uint8& t,
const char *prefix, int index, jsuword* localNames);
void trackNativeStackUse(unsigned slots);
unsigned getCallDepth() const;
- nanojit::LIns* guard(bool expected, nanojit::LIns* cond);
+ nanojit::LIns* guard(bool expected, nanojit::LIns* cond,
+ nanojit::ExitType exitType = nanojit::BRANCH_EXIT);
nanojit::LIns* addName(nanojit::LIns* ins, const char* name);
nanojit::LIns* get(jsval* p);
void set(jsval* p, nanojit::LIns* l, bool initializing = false);
bool checkType(jsval& v, uint8& type);
bool verifyTypeStability(uint8* map);
@@ -216,17 +217,17 @@ class TraceRecorder {
nanojit::LIns*& dslots_ins, nanojit::LIns* idx_ins);
void clearFrameSlotsFromCache();
public:
int backEdgeCount;
TraceRecorder(JSContext* cx, nanojit::GuardRecord*, nanojit::Fragment*, uint8* typemap);
~TraceRecorder();
- nanojit::SideExit* snapshot();
+ nanojit::SideExit* snapshot(nanojit::ExitType exitType);
nanojit::Fragment* getFragment() const { return fragment; }
bool isLoopHeader(JSContext* cx) const;
void closeLoop(nanojit::Fragmento* fragmento);
bool record_EnterFrame();
bool record_LeaveFrame();
#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \