Flexible call stack allocation with proper guarding for call stack overflows.

This commit is contained in:
Andreas Gal 2008-08-13 13:51:59 -07:00
parent 76a2288dcc
commit fa09943222
3 changed files with 26 additions and 6 deletions

View File

@ -82,6 +82,9 @@
/* Max native stack size. */
#define MAX_NATIVE_STACK_SLOTS 1024
/* Max call stack size. */
#define MAX_CALL_STACK_ENTRIES 64
#ifdef DEBUG
#define ABORT_TRACE(msg) do { fprintf(stdout, "abort: %d: %s\n", __LINE__, msg); return false; } while(0)
#else
@ -639,6 +642,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor,
cx_ins = addName(lir->insLoadi(lirbuf->state, offsetof(InterpState, cx)), "cx");
gp_ins = addName(lir->insLoadi(lirbuf->state, offsetof(InterpState, gp)), "gp");
eos_ins = addName(lir->insLoadi(lirbuf->state, offsetof(InterpState, eos)), "eos");
eor_ins = addName(lir->insLoadi(lirbuf->state, offsetof(InterpState, eor)), "eor");
/* read into registers all values on the stack and all globals we know so far */
import(ngslots, callDepth, globalTypeMap, stackTypeMap);
@ -1333,14 +1337,22 @@ TraceRecorder::emitTreeCall(Fragment* inner, GuardRecord* lr)
/* Calculate the amount we have to lift the native stack pointer by to compensate for
any outer frames that the inner tree doesn't expect but the outer tree has. */
unsigned sp_adj = nativeStackSlots(callDepth - 1, cx->fp->down) * sizeof(double);
/* Calculate the amount we have to lift the call stack by */
unsigned rp_adj = callDepth * sizeof(FrameInfo);
/* Guard that we have enough stack space for the tree we are trying to call on top
of the new value for sp. */
LIns* sp_top = lir->ins2i(LIR_add, lirbuf->sp, sp_adj +
ti->maxNativeStackSlots * sizeof(double));
guard(true, lir->ins2(LIR_lt, sp_top, eos_ins), OOM_EXIT);
/* We have enough space, so adjust sp to its new level. */
/* Guard that we have enough call stack space. */
LIns* rp_top = lir->ins2i(LIR_add, lirbuf->rp, rp_adj +
ti->maxCallDepth * sizeof(FrameInfo));
guard(true, lir->ins2(LIR_lt, rp_top, eor_ins), OOM_EXIT);
/* We have enough space, so adjust sp and rp to their new level. */
lir->insStorei(lir->ins2i(LIR_add, lirbuf->sp, sp_adj),
lirbuf->state, offsetof(InterpState, sp));
lir->insStorei(lir->ins2i(LIR_add, lirbuf->rp, rp_adj),
lirbuf->state, offsetof(InterpState, rp));
}
/* Invoke the inner tree. */
LIns* args[] = { lir->insImmPtr(inner), lirbuf->state }; /* reverse order */
@ -1351,9 +1363,11 @@ TraceRecorder::emitTreeCall(Fragment* inner, GuardRecord* lr)
SideExit* exit = lr->exit;
import(exit->numGlobalSlots, exit->calldepth,
exit->typeMap, exit->typeMap + exit->numGlobalSlots);
/* Restore state->sp to its original value (we still have it in a register). */
if (callDepth > 0)
/* Restore sp and rp to their original values (we still have them in a register). */
if (callDepth > 0) {
lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp));
lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp));
}
/* Guard that we come out of the inner tree along the same side exit we came out when
we called the inner tree at recording time. */
guard(true, lir->ins2(LIR_eq, ret, lir->insImmPtr(lr)), NESTED_EXIT);
@ -1699,6 +1713,7 @@ js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount)
double* global = (double*)alloca((globalFrameSize+1) * sizeof(double));
debug_only(*(uint64*)&global[globalFrameSize] = 0xdeadbeefdeadbeefLL;)
double* stack = (double*)alloca(MAX_NATIVE_STACK_SLOTS * sizeof(double));
#ifdef DEBUG
printf("entering trace at %s:%u@%u, native stack slots: %u\n",
cx->fp->script->filename, js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc),
@ -1715,15 +1730,18 @@ js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount)
}
return NULL;
}
ti->mismatchCount = 0;
double* entry_sp = &stack[ti->nativeStackBase/sizeof(double)];
ti->mismatchCount = 0;
FrameInfo* callstack = (FrameInfo*) alloca(ti->maxCallDepth * sizeof(FrameInfo));
double* entry_sp = &stack[ti->nativeStackBase/sizeof(double)];
//FrameInfo* callstack = (FrameInfo*) alloca(ti->maxCallDepth * sizeof(FrameInfo));
FrameInfo* callstack = (FrameInfo*) alloca(MAX_CALL_STACK_ENTRIES * sizeof(FrameInfo));
InterpState state;
state.sp = (void*)entry_sp;
state.eos = ((double*)state.sp) + MAX_NATIVE_STACK_SLOTS;
state.rp = callstack;
state.eor = callstack + MAX_CALL_STACK_ENTRIES;
state.gp = global;
state.cx = cx;
union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u;

View File

@ -216,6 +216,7 @@ class TraceRecorder {
nanojit::LIns* cx_ins;
nanojit::LIns* gp_ins;
nanojit::LIns* eos_ins;
nanojit::LIns* eor_ins;
nanojit::LIns* rval_ins;
nanojit::SideExit exit;

View File

@ -294,6 +294,7 @@ namespace avmplus
void* gp;
JSContext *cx;
void* eos;
void* eor;
};
class String