Changeset: 521e02128f87 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=521e02128f87 Modified Files: monetdb5/mal/mal_interpreter.mx Branch: Aug2011 Log Message:
Stack frame handling Documentation has been fixed, we don't use the first part of the stack frame for passing arguments aroud. They can recide anywhere on the stacks. In MAL function calls, the wrong stack frame was passed, which in case of strings and BATs would cause segfaults. It may screw up the stack frame from the caller in all other situations. diffs (173 lines): diff --git a/monetdb5/mal/mal_interpreter.mx b/monetdb5/mal/mal_interpreter.mx --- a/monetdb5/mal/mal_interpreter.mx +++ b/monetdb5/mal/mal_interpreter.mx @@ -184,7 +184,6 @@ Copy the constant values onto the stack frame Also we cannot overwrite values on the stack as this maybe part of a sequence of factory calls. -BEWARE WE ASSUME THAT FIRST VARIABLES ON THE STACK ALIGN WITH THE SIGNATURE. @= initStack for (i = @1; i < mb->vtop; i++) { lhs = &stk->stk[i]; @@ -224,7 +223,7 @@ stk->stksize = size; stk->blk = mb; - @:initStack(1)@ + @:initStack(0)@ return stk; } @@ -248,7 +247,6 @@ the minimum amount of stack space needed, some slack resources are included to permit code optimizers to add a few variables at run time, (2) copying the arguments into the new stack frame. -Notice that arguments are always the first entries on the stack. The env stackframe is set when a MAL function is called recursively. Alternatively, there is no caller but a stk to be re-used for interpretation. @@ -264,14 +262,15 @@ if (mb->vtop > stk->stksize) showScriptException(mb, 0, MAL, "stack too small\n"); pci = pcicaller; + @:initStack(env->stkbot)@ } else { - newStack(stk, mb->vsize); - stk->stktop = mb->vtop; - stk->stksize = mb->vsize; + stk= prepareMALstack(mb, mb->vsize); + if (stk == 0) + throw(MAL,"mal.interpreter",MAL_STACK_FAIL); stk->blk = mb; stk->cmd = cntxt->itrace; /* set debug mode */ + /*safeguardStack*/ if (env) { - /*safeguardStack*/ stk->stkdepth = stk->stksize + env->stkdepth; stk->calldepth = env->calldepth + 1; if (stk->calldepth > 256) @@ -280,22 +279,29 @@ /* we are running low on stack space */ throw(MAL, "mal.interpreter", MAL_STACK_FAIL); } +@- +An optimization is to copy all constant variables used in functions immediately +onto the value stack. Then we do not have to check for their location +later on any more. At some point, the effect is optimal, if at least several +constants are referenced in a function (a gain on tst400a of 20% has been +observed due the small size of the function). +@c } if (env && mbcaller) { InstrPtr pp; int k; @- -Beware, a function signature f(a1..an):(b1..bn) is parsed in such a way that -the symbol table and stackframe contains the sequence -f,a1..an,b1..bn. This slightly complicates the implementation -of the return statement. +Moreover, we have to copy the result types to the stack for later +use. The stack value has been cleared to avoid misinterpretation of left-over +information. Since a stack frame may contain values of a previous call, +we should first remove garbage. @c pci = pcicaller; pp = getInstrPtr(mb, 0); /* set return types */ for (i = 0; i < pci->retc; i++) { - lhs = &stk->stk[i]; + lhs = &stk->stk[pp->argv[i]]; lhs->vtype = getVarGDKType(mb, i); } for (k = pp->retc; i < pci->argc; i++, k++) { @@ -310,25 +316,6 @@ } stk->up = env; } -@- -An optimization is to copy all constant variables used in functions immediately -onto the value stack. Then we do not have to check for their location -later on any more. At some point, the effect is optimal, if at least several -constants are referenced in a function (a gain on tst400a of 20% has been -observed due the small size of the function). - -Moreover, we have to copy the result types to the stack for later -use. The stack value is cleared to avoid misinterpretation of left-over -information. Since a stack frame may contain values of a previous call, -we should first remove garbage. -@c - if (env && mbcaller) { - @:initStack(pci->argc)@ - } else if (env && env->stkbot) { - @:initStack(env->stkbot)@ - } else { - @:initStack(mbcaller ? pci->argc:1)@ - } if (stk->cmd && env && stk->cmd != 'f') stk->cmd = env->cmd; @@ -388,7 +375,7 @@ MalStkPtr stk = NULL; str ret = MAL_SUCCEED; int i; - ValPtr lhs, rhs; + ValPtr lhs; InstrPtr pci = getInstrPtr(mb, 0); @:performanceVariables@ @@ -405,13 +392,8 @@ all arguments and return values. @c if (*env == NULL) { - stk = newGlobalStack(mb->vsize); - memset((char *)stk, 0, stackSize(mb->vtop)); - stk->stktop = mb->vtop; - stk->stksize = mb->vsize; - stk->blk = mb; + stk = prepareMALstack(mb, mb->vsize); stk->up = 0; - @:initStack(pci->argc)@ *env = stk; } else stk = *env; assert(stk); @@ -2042,10 +2024,37 @@ @- @= functioncall -{ +{ MalStkPtr nstk; + InstrPtr q; + int ii, arg; + stk->pcup = stkpc; @:safeTarget(@1)@ - ret = runMAL(cntxt, pci->blk, 1, mb, stk, pci); + nstk = prepareMALstack(pci->blk, pci->blk->vsize); + if (nstk == 0) + throw(MAL,"mal.interpreter",MAL_STACK_FAIL); + + /*safeguardStack*/ + nstk->stkdepth = nstk->stksize + stk->stkdepth; + nstk->calldepth = stk->calldepth + 1; + if (nstk->calldepth > 256) + throw(MAL, "mal.interpreter", MAL_CALLDEPTH_FAIL); + if ((unsigned)nstk->stkdepth > THREAD_STACK_SIZE / sizeof(mb->var[0]) / 4 && THRhighwater()) + /* we are running low on stack space */ + throw(MAL, "mal.interpreter", MAL_STACK_FAIL); + + /* copy arguments onto destination stack */ + q= getInstrPtr(pci->blk,0); + arg = q->retc; + for (ii = pci->retc; ii < pci->argc; ii++,arg++) { + lhs = &nstk->stk[q->argv[arg]]; + rhs = &stk->stk[pci->argv[ii]]; + VALcopy(lhs, rhs); + if (lhs->vtype == TYPE_bat) + BBPincref(lhs->val.bval, TRUE); + } + ret = runMALsequence(cntxt, pci->blk, 1, pci->blk->stop, nstk, stk, pci); + GDKfree(nstk); @:restoreTarget(@1,@3)@ @:exceptionHndlr(@1,@2,@3)@ @:timingHndlr(@1)@ _______________________________________________ Checkin-list mailing list Checkin-list@monetdb.org http://mail.monetdb.org/mailman/listinfo/checkin-list