1
0
Fork 0
forked from fte/fteqw

Rewrite fork/resume logic to not bug out when the qc used alloca.

This commit is contained in:
Shpoike 2024-12-28 15:55:29 +00:00
parent affb96a3b3
commit 6e35299bf8
2 changed files with 105 additions and 108 deletions

View file

@ -1673,7 +1673,7 @@ reeval:
break;
case OP_PUSH: //note: OPA is words, not bytes.
OPC->_int = ENGINEPOINTER(&prinst.localstack[prinst.localstack_used+prinst.spushed]);
prinst.spushed += OPA->_int;
prinst.spushed += OPA->_uint;
if (prinst.spushed + prinst.localstack_used >= LOCALSTACK_SIZE)
{
i = prinst.spushed;
@ -1683,7 +1683,7 @@ reeval:
}
break;
/* case OP_POP:
pr_spushed -= OPA->_int;
pr_spushed -= OPA->_uint;
if (pr_spushed < 0)
{
pr_spushed = 0;

View file

@ -1919,99 +1919,130 @@ typedef struct qcthread_s {
qcthreadstack_t fstack[MAX_STACK_DEPTH];
int lstackused;
int lstack[LOCALSTACK_SIZE];
int xstatement;
int xfunction;
progsnum_t xprogs;
} qcthread_t;
struct qcthread_s *PDECL PR_ForkStack(pubprogfuncs_t *ppf)
{ //QC code can call builtins that call qc code.
//to get around the problems of restoring the builtins we simply don't save the thread over the builtin.
//this may be an error when OP_PUSH has been used.
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
int i, l;
int i, pushed;
int ed = prinst.exitdepth;
int localsoffset, baselocalsoffset;
qcthread_t *thread = externs->memalloc(sizeof(qcthread_t));
const mfunction_t *f;
//notes:
//pr_stack[prinst.exitdepth] is a dummy entry, with null function refs. we don't care about it.
//pr_stack[pr_depth] is technically invalid but logically required - it refers to the current function instead. stoopid extra indirection.
//[pr_depth] is the qc function that called whichever builtin we're executing right now so we want that (logical) one. [0] is irrelevant though.
//entering a function copys its locals into the local stack for restoration on return, any OP_PUSHED stuff within the frame is then after that.
//OP_PUSH/'pushed' is the PARENT function's pushes. f->locals stuff is the CHILD function's pushes.
//copy out the functions stack.
for (i = 0,localsoffset=0; i < ed; i++)
for (i = 1,localsoffset=0; i <= ed; i++)
{
if (i+1 == prinst.pr_depth)
if (i == prinst.pr_depth)
{
localsoffset += prinst.spushed;
f = prinst.pr_xfunction;
else
f = prinst.pr_stack[i+1].f;
localsoffset += f->locals; //this is where it crashes
localsoffset += f->locals;
}
else
{
localsoffset += prinst.pr_stack[i].pushed;
f = prinst.pr_stack[i].f;
if (f)
localsoffset += f->locals;
}
}
//now we can start copying the stack.
baselocalsoffset = localsoffset;
for (i = ed; i < prinst.pr_depth; i++)
thread->fstackdepth = 0;
for (; i <= prinst.pr_depth; i++)
{
thread->fstack[i-ed].fnum = prinst.pr_stack[i].f - pr_progstate[prinst.pr_stack[i].progsnum].functions;
thread->fstack[i-ed].progsnum = prinst.pr_stack[i].progsnum;
thread->fstack[i-ed].statement = prinst.pr_stack[i].s;
thread->fstack[i-ed].spushed = prinst.pr_stack[i].pushed;
if (i == prinst.pr_depth)
{ //top of the stack. whichever function called the builtin we're executing.
thread->fstack[thread->fstackdepth].fnum = prinst.pr_xfunction - current_progstate->functions;
thread->fstack[thread->fstackdepth].progsnum = prinst.pr_typecurrent;
thread->fstack[thread->fstackdepth].statement = prinst.pr_xstatement;
thread->fstack[thread->fstackdepth].spushed = prinst.spushed;
thread->fstackdepth++;
if (i+1 == prinst.pr_depth)
localsoffset += prinst.spushed;
f = prinst.pr_xfunction;
else
f = prinst.pr_stack[i+1].f;
localsoffset += f->locals;
}
thread->fstackdepth = prinst.pr_depth - ed;
for (i = prinst.pr_depth - 1; i >= ed ; i--)
{
if (i+1 == prinst.pr_depth)
f = prinst.pr_xfunction;
else
f = prinst.pr_stack[i+1].f;
{
thread->fstack[thread->fstackdepth].fnum = prinst.pr_stack[i].f - pr_progstate[prinst.pr_stack[i].progsnum].functions;
thread->fstack[thread->fstackdepth].progsnum = prinst.pr_stack[i].progsnum;
thread->fstack[thread->fstackdepth].statement = prinst.pr_stack[i].s;
thread->fstack[thread->fstackdepth].spushed = prinst.pr_stack[i].pushed;
thread->fstackdepth++;
localsoffset += prinst.pr_stack[i].pushed;
f = prinst.pr_stack[i].f;
localsoffset += f->locals;
}
}
//we now know how many locals we need... but life is not easy.
//preserving on entry means the definitive location is the pr_globals - and they'll have been 'corrupted' by any child functions.
//so we need to unwind(rewind) them here to find their proper 'current' values, so that resumption can rebuild the execution stack on resume to revert them properly to their prior values. messy.
for (i = prinst.pr_depth; i > ed ; i--)
{
if (i == prinst.pr_depth)
f = prinst.pr_xfunction, pushed = prinst.spushed;
else
f = prinst.pr_stack[i].f, pushed = prinst.pr_stack[i].pushed;
//preseve any OP_PUSH stuff
localsoffset -= pushed;
memcpy(&thread->lstack[localsoffset-baselocalsoffset], prinst.localstack+localsoffset, pushed*sizeof(int));
//preserve the current locals
localsoffset -= f->locals;
for (l = 0; l < f->locals; l++)
{
thread->lstack[localsoffset-baselocalsoffset + l ] = ((int *)pr_globals)[f->parm_start + l];
((int *)pr_globals)[f->parm_start + l] = prinst.localstack[localsoffset+l]; //copy the old value into the globals (so the older functions have the correct locals.
}
memcpy(&thread->lstack[localsoffset-baselocalsoffset], ((int *)pr_globals)+f->parm_start, f->locals*sizeof(int));
//unwind the locals so parent functions we preserve have the proper current values.
memcpy(((int *)pr_globals)+f->parm_start, prinst.localstack+localsoffset, f->locals*sizeof(int));
}
for (i = ed; i < prinst.pr_depth ; i++) //we need to get the locals back to how they were.
//rewind the locals so they don't get corrupt when returning from fork etc.
for (i = ed+1; i <= prinst.pr_depth ; i++) //we need to get the locals back to how they were.
{
if (i+1 == prinst.pr_depth)
f = prinst.pr_xfunction;
if (i == prinst.pr_depth)
f = prinst.pr_xfunction, pushed = prinst.spushed;
else
f = prinst.pr_stack[i+1].f;
f = prinst.pr_stack[i].f, pushed = prinst.pr_stack[i].pushed;
for (l = 0; l < f->locals; l++)
{
((int *)pr_globals)[f->parm_start + l] = thread->lstack[localsoffset-baselocalsoffset + l];
}
memcpy(((int *)pr_globals)+f->parm_start, &thread->lstack[localsoffset-baselocalsoffset], f->locals*sizeof(int));
localsoffset += f->locals;
localsoffset += pushed; //we didn't need to clobber this, just skip it to avoid corrupting.
}
thread->lstackused = localsoffset - baselocalsoffset;
thread->xstatement = prinst.pr_xstatement;
thread->xfunction = prinst.pr_xfunction - current_progstate->functions;
thread->xprogs = prinst.pr_typecurrent;
return thread;
}
void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
mfunction_t *f, *oldf;
int i,l,ls, olds, oldp;
progsnum_t initial_progs;
mfunction_t *f;
int i;
progsnum_t initial_progs = prinst.pr_typecurrent;
unsigned int initial_stack;
int oldexitdepth;
int *glob;
int s;
#ifndef QCGC
int tempdepth;
#endif
progsnum_t prnum = thread->xprogs;
int fnum = thread->xfunction;
if (prinst.localstack_used + thread->lstackused > LOCALSTACK_SIZE)
PR_RunError(&progfuncs->funcs, "Too many locals on resumtion of QC thread\n");
@ -2020,79 +2051,48 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
//do progs switching stuff as appropriate. (fteqw only)
initial_progs = prinst.pr_typecurrent;
PR_SwitchProgsParms(progfuncs, prnum);
oldexitdepth = prinst.exitdepth;
prinst.exitdepth = prinst.pr_depth;
ls = 0;
initial_stack = prinst.localstack_used;
//add on the callstack.
for (i = 0; i < thread->fstackdepth; i++)
{
if (prinst.pr_depth == prinst.exitdepth)
{
//make the new stack frame from the working values so stuff gets restored properly...
prinst.pr_stack[prinst.pr_depth].f = prinst.pr_xfunction;
prinst.pr_stack[prinst.pr_depth].s = prinst.pr_xstatement;
prinst.pr_stack[prinst.pr_depth].progsnum = initial_progs;
prinst.pr_stack[prinst.pr_depth].pushed = prinst.spushed;
}
else
{
prinst.pr_stack[prinst.pr_depth].progsnum = thread->fstack[i].progsnum;
prinst.pr_stack[prinst.pr_depth].f = pr_progstate[thread->fstack[i].progsnum].functions + thread->fstack[i].fnum;
prinst.pr_stack[prinst.pr_depth].s = thread->fstack[i].statement;
prinst.pr_stack[prinst.pr_depth].pushed = thread->fstack[i].spushed;
}
if (i+1 == thread->fstackdepth)
{
f = &pr_cp_functions[fnum];
glob = (int*)pr_globals;
}
else
{
f = pr_progstate[thread->fstack[i+1].progsnum].functions + thread->fstack[i+1].fnum;
glob = (int*)pr_progstate[thread->fstack[i+1].progsnum].globals;
}
for (l = 0; l < f->locals; l++)
{
prinst.localstack[prinst.localstack_used++] = glob[f->parm_start + l];
glob[f->parm_start + l] = thread->lstack[ls++];
}
prinst.pr_depth++;
//restore the OP_PUSH data
memcpy(&prinst.localstack[prinst.localstack_used], &thread->lstack[prinst.localstack_used-initial_stack], prinst.spushed*sizeof(int));
prinst.localstack_used += prinst.spushed;
//and refill the working values from the inbound stack
PR_SwitchProgs(progfuncs, thread->fstack[i].progsnum);
prinst.pr_xfunction = pr_progstate[thread->fstack[i].progsnum].functions + thread->fstack[i].fnum;
prinst.pr_xstatement = thread->fstack[i].statement;
prinst.spushed = thread->fstack[i].spushed;
f = pr_progstate[thread->fstack[i].progsnum].functions + thread->fstack[i].fnum;
glob = (int*)pr_progstate[thread->fstack[i].progsnum].globals;
//copy the 'new' function's current globals into the local stack for restoration
memcpy(&prinst.localstack[prinst.localstack_used], &glob[f->parm_start], sizeof(int)*f->locals);
//and overwrite them with the saved values.
memcpy(&glob[f->parm_start], &thread->lstack[prinst.localstack_used-initial_stack], sizeof(int)*f->locals);
prinst.localstack_used += f->locals;
}
if (ls != thread->lstackused)
if (prinst.localstack_used-initial_stack != thread->lstackused)
PR_RunError(&progfuncs->funcs, "Thread stores incorrect locals count\n");
f = &pr_cp_functions[fnum];
// thread->lstackused -= f->locals; //the current function is the odd one out.
//add on the locals stack
// memcpy(prinst.localstack+prinst.localstack_used, thread->lstack, sizeof(int)*thread->lstackused);
// prinst.localstack_used += thread->lstackused;
//bung the locals of the current function on the stack.
// for (i=0 ; i < f->locals ; i++)
// ((int *)pr_globals)[f->parm_start + i] = 0xff00ff00;//thread->lstack[thread->lstackused+i];
// PR_EnterFunction (progfuncs, f, initial_progs);
oldf = prinst.pr_xfunction;
olds = prinst.pr_xstatement;
oldp = prinst.spushed;
prinst.pr_xfunction = f;
s = thread->xstatement;
#ifndef QCGC
tempdepth = prinst.numtempstringsstack;
#endif
PR_ExecuteCode(progfuncs, s);
PR_ExecuteCode(progfuncs, prinst.pr_xstatement);
PR_SwitchProgsParms(progfuncs, initial_progs);
@ -2102,9 +2102,6 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
#endif
prinst.exitdepth = oldexitdepth;
prinst.pr_xfunction = oldf;
prinst.pr_xstatement = olds;
prinst.spushed = oldp;
}
void PDECL PR_AbortStack (pubprogfuncs_t *ppf)