mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Flexible call stack allocation with proper guarding for call stack overflows.
This commit is contained in:
parent
76a2288dcc
commit
fa09943222
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -294,6 +294,7 @@ namespace avmplus
|
||||
void* gp;
|
||||
JSContext *cx;
|
||||
void* eos;
|
||||
void* eor;
|
||||
};
|
||||
|
||||
class String
|
||||
|
Loading…
Reference in New Issue
Block a user