/* ************************************************************************* */ VerticalBlockMatrix SymmetricBlockMatrix::choleskyPartial( DenseIndex nFrontals) { // Do dense elimination if (blockStart() != 0) throw std::invalid_argument( "Can only do Cholesky when the SymmetricBlockMatrix is not a restricted view, i.e. when blockStart == 0."); if (!gtsam::choleskyPartial(matrix_, offset(nFrontals))) throw CholeskyFailed(); // Split conditional // Create one big conditionals with many frontal variables. gttic(Construct_conditional); const size_t varDim = offset(nFrontals); VerticalBlockMatrix Ab = VerticalBlockMatrix::LikeActiveViewOf(*this, varDim); Ab.full() = matrix_.topRows(varDim); Ab.full().triangularView<Eigen::StrictlyLower>().setZero(); gttoc(Construct_conditional); gttic(Remaining_factor); // Take lower-right block of Ab_ to get the remaining factor blockStart() = nFrontals; gttoc(Remaining_factor); return Ab; }
/* barrier blocks can only be dropped when they are fully excluded. */ static str OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb) { /* catch and remove constant bounded blocks */ int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1; InstrPtr p; str msg = MAL_SUCCEED; while(multipass--){ block = -1; skip = 0; j = 0; for (i = 0; i < mb->stop; i++) { p = mb->stmt[i]; if (blockExit(p) && block == getArg(p,0) ){ block = -1; skip = 0; freeInstruction(p); mb->stmt[i]= 0; continue; } if (p->argc == 2 && blockStart(p) && block < 0 && isVarConstant(mb, getArg(p, 1)) && getArgType(mb, p, 1) == TYPE_bit ){ if( getVarConstant(mb, getArg(p, 1)).val.btval == 0) { block = getArg(p,0); skip ++; action++; } // Try to remove the barrier statement itself (when true). if ( getVarConstant(mb, getArg(p, 1)).val.btval == 1 && OPTsimpleflow(mb,i)) { block = getArg(p,0); skip = 0; action++; freeInstruction(p); mb->stmt[i]= 0; continue; } } else if( p->argc == 2 && blockStart(p) && block >= 0 && skip == 0 && isVarConstant(mb, getArg(p, 1)) && getArgType(mb, p, 1) == TYPE_bit && multipass == 0) multipass++; if (skip){ freeInstruction(p); mb->stmt[i]= 0; } else mb->stmt[j++] = p; } mb->stop = j; for (; j < i; j++) mb->stmt[j] = NULL; } if (action) chkTypes(cntxt->usermodule, mb, TRUE); return msg; }
/* barrier blocks can only be dropped when they are fully excluded. */ static int OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb) { /* catch and remove constant bounded blocks */ int i, j = 0, action = 0, block = 0, skip = 0, top =0, skiplist[10]; InstrPtr p; for (i = 0; i < mb->stop; i++) { p = mb->stmt[i]; if (blockStart(p)) { block++; if (p->argc == 2 && isVarConstant(mb, getArg(p, 1)) && getArgType(mb, p, 1) == TYPE_bit && getVarConstant(mb, getArg(p, 1)).val.btval == 0) { if (skip == 0) skip = block; action++; } // Try to remove the barrier statement itself (when true). if (p->argc == 2 && isVarConstant(mb, getArg(p, 1)) && getArgType(mb, p, 1) == TYPE_bit && getVarConstant(mb, getArg(p, 1)).val.btval == 1 && top <10 && OPTsimpleflow(mb,i)) { skiplist[top++]= getArg(p,0); freeInstruction(p); continue; } } if (blockExit(p)) { if (top > 0 && skiplist[top-1] == getArg(p,0) ){ top--; freeInstruction(p); continue; } if (skip ) freeInstruction(p); else mb->stmt[j++] = p; if (skip == block) skip = 0; block--; if (block == 0) skip = 0; } else if (skip) freeInstruction(p); else mb->stmt[j++] = p; } mb->stop = j; for (; j < i; j++) mb->stmt[j] = NULL; if (action) { chkTypes(cntxt->fdout, cntxt->nspace, mb, TRUE); return mb->errors ? 0 : action; } return action; }
// http://www.w3.org/TR/css3-syntax/#consume-an-ident-like-token MediaQueryToken MediaQueryTokenizer::consumeIdentLikeToken() { String name = consumeName(); if (consumeIfNext('(')) { return blockStart(LeftParenthesisToken, FunctionToken, name); } return MediaQueryToken(IdentToken, name); }
// http://dev.w3.org/csswg/css-syntax/#consume-ident-like-token CSSParserToken CSSTokenizer::consumeIdentLikeToken() { CSSParserString name = consumeName(); if (consumeIfNext('(')) { if (name.equalIgnoringASCIICase("url")) { // The spec is slightly different so as to avoid dropping whitespace // tokens, but they wouldn't be used and this is easier. consumeUntilNonWhitespace(); UChar next = m_input.nextInputChar(); if (next != '"' && next != '\'') return consumeUrlToken(); } return blockStart(LeftParenthesisToken, FunctionToken, name); } return CSSParserToken(IdentToken, name); }
static int OPTsimpleflow(MalBlkPtr mb, int pc) { int i, block =0, simple= TRUE; InstrPtr p; for ( i= pc; i< mb->stop; i++){ p =getInstrPtr(mb,i); if (blockStart(p)) block++; if ( blockExit(p)) block--; if ( blockCntrl(p)) simple= FALSE; if ( block == 0){ return simple; } } return FALSE; }
CSSParserToken CSSTokenizer::leftBrace(UChar cc) { return blockStart(LeftBraceToken); }
CSSParserToken CSSTokenizer::leftParenthesis(UChar cc) { return blockStart(LeftParenthesisToken); }
MediaQueryToken MediaQueryTokenizer::leftParenthesis(UChar cc) { return blockStart(LeftParenthesisToken); }
MediaQueryToken MediaQueryTokenizer::leftBrace(UChar cc) { return blockStart(LeftBraceToken); }
int OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { InstrPtr p; int i, k, limit, *alias, barrier; MalStkPtr env = NULL; int profiler; str msg; int debugstate = cntxt->itrace, actions = 0, constantblock = 0; int *assigned, setonce; cntxt->itrace = 0; (void)stk; (void)pci; if (varGetProp(mb, getArg(mb->stmt[0], 0), inlineProp) != NULL) return 0; (void)cntxt; OPTDEBUGevaluate mnstr_printf(cntxt->fdout, "Constant expression optimizer started\n"); assigned = (int*) GDKzalloc(sizeof(int) * mb->vtop); if (assigned == NULL) return 0; alias = (int*)GDKzalloc(mb->vsize * sizeof(int) * 2); /* we introduce more */ if (alias == NULL){ GDKfree(assigned); return 0; } // arguments are implicitly assigned by context p = getInstrPtr(mb, 0); for ( k =p->retc; k < p->argc; k++) assigned[getArg(p,k)]++; limit = mb->stop; for (i = 1; i < limit; i++) { p = getInstrPtr(mb, i); // The double count emerging from a barrier exit is ignored. if (! blockExit(p) || (blockExit(p) && p->retc != p->argc)) for ( k =0; k < p->retc; k++) assigned[getArg(p,k)]++; } for (i = 1; i < limit; i++) { p = getInstrPtr(mb, i); for (k = p->retc; k < p->argc; k++) if (alias[getArg(p, k)]) getArg(p, k) = alias[getArg(p, k)]; // to avoid management of duplicate assignments over multiple blocks // we limit ourselfs to evaluation of the first assignment only. setonce = assigned[getArg(p,0)] == 1; OPTDEBUGevaluate printInstruction(cntxt->fdout, mb, 0, p, LIST_MAL_ALL); constantblock += blockStart(p) && OPTallConstant(cntxt,mb,p); /* be aware that you only assign once to a variable */ if (setonce && p->retc == 1 && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) { barrier = p->barrier; p->barrier = 0; profiler = malProfileMode; /* we don't trace it */ malProfileMode = 0; if ( env == NULL) { env = prepareMALstack(mb, 2 * mb->vsize ); env->keepAlive = TRUE; } msg = reenterMAL(cntxt, mb, i, i + 1, env); malProfileMode= profiler; p->barrier = barrier; OPTDEBUGevaluate { mnstr_printf(cntxt->fdout, "#retc var %s\n", getVarName(mb, getArg(p, 0))); mnstr_printf(cntxt->fdout, "#result:%s\n", msg == MAL_SUCCEED ? "ok" : msg); } if (msg == MAL_SUCCEED) { int nvar; ValRecord cst; actions++; cst.vtype = 0; VALcopy(&cst, &env->stk[getArg(p, 0)]); /* You may not overwrite constants. They may be used by * other instructions */ nvar = getArg(p, 1) = defConstant(mb, getArgType(mb, p, 0), &cst); if (nvar >= env->stktop) { VALcopy(&env->stk[getArg(p, 1)], &getVarConstant(mb, getArg(p, 1))); env->stktop = getArg(p, 1) + 1; } alias[getArg(p, 0)] = getArg(p, 1); p->argc = 2; p->token = ASSIGNsymbol; clrFunction(p); p->barrier = barrier; /* freeze the type */ setVarFixed(mb,getArg(p,1)); setVarUDFtype(mb,getArg(p,1)); OPTDEBUGevaluate { mnstr_printf(cntxt->fdout, "Evaluated new constant=%d -> %d:%s\n", getArg(p, 0), getArg(p, 1), getTypeName(getArgType(mb, p, 1))); } } else {
str OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { InstrPtr p; int i, k, limit, *alias = 0, barrier; MalStkPtr env = NULL; int profiler; int debugstate = cntxt->itrace, actions = 0, constantblock = 0; int *assigned = 0, use; char buf[256]; lng usec = GDKusec(); str msg = MAL_SUCCEED; (void)stk; (void)pci; if ( mb->inlineProp ) return MAL_SUCCEED; cntxt->itrace = 0; #ifdef DEBUG_OPT_EVALUATE fprintf(stderr, "Constant expression optimizer started\n"); #endif assigned = (int*) GDKzalloc(sizeof(int) * mb->vtop); if (assigned == NULL) throw(MAL,"optimzier.evaluate", SQLSTATE(HY001) MAL_MALLOC_FAIL); alias = (int*)GDKzalloc(mb->vsize * sizeof(int) * 2); /* we introduce more */ if (alias == NULL){ GDKfree(assigned); throw(MAL,"optimzier.evaluate", SQLSTATE(HY001) MAL_MALLOC_FAIL); } // arguments are implicitly assigned by context p = getInstrPtr(mb, 0); for ( k =p->retc; k < p->argc; k++) assigned[getArg(p,k)]++; limit = mb->stop; for (i = 1; i < limit; i++) { p = getInstrPtr(mb, i); // The double count emerging from a barrier exit is ignored. if (! blockExit(p) || (blockExit(p) && p->retc != p->argc)) for ( k =0; k < p->retc; k++) if ( p->retc != p->argc || p->token != ASSIGNsymbol ) assigned[getArg(p,k)]++; } for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) { p = getInstrPtr(mb, i); // to avoid management of duplicate assignments over multiple blocks // we limit ourselves to evaluation of the first assignment only. use = assigned[getArg(p,0)] == 1 && !(p->argc == p->retc && blockExit(p)); for (k = p->retc; k < p->argc; k++) if (alias[getArg(p, k)]) getArg(p, k) = alias[getArg(p, k)]; #ifdef DEBUG_OPT_EVALUATE fprintInstruction(stderr , mb, 0, p, LIST_MAL_ALL); #endif /* be aware that you only assign once to a variable */ if (use && p->retc == 1 && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) { barrier = p->barrier; p->barrier = 0; profiler = malProfileMode; /* we don't trace it */ malProfileMode = 0; if ( env == NULL) { env = prepareMALstack(mb, 2 * mb->vsize); if (!env) { msg = createException(MAL,"optimizer.evaluate", SQLSTATE(HY001) MAL_MALLOC_FAIL); goto wrapup; } env->keepAlive = TRUE; } msg = reenterMAL(cntxt, mb, i, i + 1, env); malProfileMode= profiler; p->barrier = barrier; #ifdef DEBUG_OPT_EVALUATE fprintf(stderr, "#retc var %s\n", getVarName(mb, getArg(p, 0))); fprintf(stderr, "#result:%s\n", msg == MAL_SUCCEED ? "ok" : msg); #endif if (msg == MAL_SUCCEED) { int nvar; ValRecord cst; actions++; cst.vtype = 0; VALcopy(&cst, &env->stk[getArg(p, 0)]); /* You may not overwrite constants. They may be used by * other instructions */ nvar = getArg(p, 1) = defConstant(mb, getArgType(mb, p, 0), &cst); if (nvar >= env->stktop) { VALcopy(&env->stk[getArg(p, 1)], &getVarConstant(mb, getArg(p, 1))); env->stktop = getArg(p, 1) + 1; } alias[getArg(p, 0)] = getArg(p, 1); p->argc = 2; p->token = ASSIGNsymbol; clrFunction(p); p->barrier = barrier; /* freeze the type */ setVarFixed(mb,getArg(p,1)); setVarUDFtype(mb,getArg(p,1)); #ifdef DEBUG_OPT_EVALUATE {str tpename; fprintf(stderr, "Evaluated new constant=%d -> %d:%s\n", getArg(p, 0), getArg(p, 1), tpename = getTypeName(getArgType(mb, p, 1))); GDKfree(tpename); } #endif } else { /* if there is an error, we should postpone message handling, as the actual error (eg. division by zero ) may not happen) */ #ifdef DEBUG_OPT_EVALUATE fprintf(stderr, "Evaluated %s\n", msg); #endif freeException(msg); msg= MAL_SUCCEED; mb->errors = 0; } } constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */ } // produces errors in SQL when enabled if ( constantblock) msg = OPTremoveUnusedBlocks(cntxt, mb); cntxt->itrace = debugstate; /* Defense line against incorrect plans */ /* Plan is unaffected */ chkTypes(cntxt->usermodule, mb, FALSE); chkFlow(mb); chkDeclarations(mb); /* keep all actions taken as a post block comment */ usec = GDKusec()- usec; snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec","evaluate",actions,usec); newComment(mb,buf); if( actions >= 0) addtoMalBlkHistory(mb); wrapup: if ( env) freeStack(env); if(assigned) GDKfree(assigned); if(alias) GDKfree(alias); return msg; }
int OPTstrengthReductionImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j = 0, k, se= FALSE; InstrPtr p; int bk, ik, blk, blkbegin, blkexit, actions = 0; InstrPtr *before, *within, *old = mb->stmt; Lifespan span; (void) cntxt; (void) pci; (void) stk; /* to fool compilers */ before = (InstrPtr *) GDKmalloc((mb->ssize + 1) * sizeof(InstrPtr)); within = (InstrPtr *) GDKmalloc((mb->ssize + 1) * sizeof(InstrPtr)); if (before== NULL || within == NULL){ if(before) GDKfree(before); if(within) GDKfree(within); return 0; } bk = 0; ik = 0; blk = 0; blkexit= blkbegin = 0; for (i = 0; i < mb->stop; i++) before[i] = within[i] = 0; before[bk++] = getInstrPtr(mb, 0); span =setLifespan(mb); if( span == NULL) return 0; for (i = 1; i < mb->stop - 1; i++) { p = getInstrPtr(mb, i); if (blockStart(p)) { if (blkbegin == 0){ if( isLoopBarrier(mb,i) ){ blkbegin = i; blkexit = getBlockExit(mb,i); } OPTDEBUGstrengthReduction mnstr_printf(cntxt->fdout, "#check block %d-%d\n", blkbegin, blkexit); } within[ik++] = p; blk++; continue; } if (blockExit(p)) { blk--; if (blk == 0) blkexit= blkbegin = 0; /* move the saved instruction into place */ OPTDEBUGstrengthReduction mnstr_printf(cntxt->fdout, "#combine both %d %d\n", bk, ik); for (k = 0; k < ik; k++) before[bk++] = within[k]; ik = 0; before[bk++] = p; continue; } /* * @- * Strength reduction is only relevant inside a block; */ if( blkexit == 0) { within[ik++] = p; continue; } /* * @- * Flow control statements may not be moved around */ if ( p->barrier != 0){ within[ik++] = p; continue; } /* * @- * Limit strength reduction to the type modules and the batcalc, batstr, batcolor * and sql.bind. */ if(getModuleId(p) && !isNewSource(p) ) { within[ik++] = p; continue; } /* * @- * Search the prospective new block and make sure that * none of the arguments is assigned a value. */ for (j = ik-1; j > 0; j--) { InstrPtr q = within[j]; for (k = 0; k < q->retc; k++) if (SRoverwritten(p, getArg(q, k))) { se = TRUE; OPTDEBUGstrengthReduction mnstr_printf(cntxt->fdout, "variable is set in loop %d\n", getArg(p, k)); goto noreduction; } } /* * @- * Make sure the variables are not declared before the loop and used * after the loop, because then you may not simple move an expression. */ for (k = 0; k < p->retc; k++) if ( getBeginLifespan(span, getArg(p, k))<= blkbegin || getEndLifespan(span, getArg(p, k))> blkexit) { se = TRUE; OPTDEBUGstrengthReduction mnstr_printf(cntxt->fdout, "variable %d may not be moved %d-%d\n", getArg(p, k),getBeginLifespan(span, getArg(p, k)), getEndLifespan(span, getArg(p, k))); goto noreduction; } noreduction: OPTDEBUGstrengthReduction{ mnstr_printf(cntxt->fdout,"move %d to stack %s\n", i, (se ?"within":"before")); printInstruction(cntxt->fdout, mb, 0, p, LIST_MAL_ALL); } if (blkexit && se == FALSE && !hasSideEffects(p, TRUE) && !isUpdateInstruction(p) ) before[bk++] = p; else within[ik++] = p; } actions += ik; for (k = 0; k < ik; k++) before[bk++] = within[k]; before[bk++] = getInstrPtr(mb, i); GDKfree(mb->stmt); mb->stmt = (InstrPtr *) GDKzalloc((mb->ssize) * sizeof(InstrPtr)); if ( mb->stmt == NULL){ GDKfree(span); GDKfree(before); GDKfree(within); mb->stmt = old; return 0; } mb->stop = 0; OPTDEBUGstrengthReduction mnstr_printf(cntxt->fdout,"stop= %d bk=%d\n",mb->stop,bk); for (i = 0; i < bk; i++) if( before[i]) pushInstruction(mb, before[i]); GDKfree(span); GDKfree(before); GDKfree(within); return actions; }
void blockStart() { FOREACH blockStart(); }
/* * Keeping variables around beyond their end-of-life-span * can be marked with the proper 'keep'. */ int OPTgarbageCollectorImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j, k, n = 0, limit, vlimit, depth=0, slimit; InstrPtr p, q, *old; int actions = 0; Lifespan span; (void) pci; (void) cntxt; (void) stk; if (varGetProp(mb, getArg(mb->stmt[0], 0), inlineProp) != NULL) return 0; span = setLifespan(mb); if ( span == NULL) return 0; old= mb->stmt; limit = mb->stop; slimit = mb->ssize; vlimit = mb->vtop; if ( newMalBlkStmt(mb,mb->ssize) < 0) { GDKfree(span); return 0; } p = NULL; for (i = 0; i < limit; i++) { p = old[i]; p->gc &= ~GARBAGECONTROL; if ( p->barrier == RETURNsymbol){ pushInstruction(mb, p); continue; } if (blockStart(p) ) depth++; if ( p->token == ENDsymbol) break; pushInstruction(mb, p); n = mb->stop-1; for (j = 0; j < p->argc; j++) { if (getEndLifespan(span,getArg(p,j)) == i && isaBatType(getArgType(mb, p, j)) ){ mb->var[getArg(p,j)]->eolife = n; p->gc |= GARBAGECONTROL; } } if (blockExit(p) ){ /* force garbage collection of all within upper block */ depth--; for (k = 0; k < vlimit; k++) { if (getBeginLifespan(span,k) > 0 && getEndLifespan(span,k) == i && isaBatType(getVarType(mb,k)) && varGetProp(mb, k, keepProp) == NULL){ q= newAssignment(mb); getArg(q,0) = k; setVarUDFtype(mb,k); setVarFixed(mb,k); q= pushNil(mb,q, getVarType(mb,k)); q->gc |= GARBAGECONTROL; mb->var[k]->eolife = mb->stop-1; actions++; } } } } assert(p); assert( p->token == ENDsymbol); pushInstruction(mb, p); for (i++; i < limit; i++) pushInstruction(mb, old[i]); for (; i < slimit; i++) if (old[i]) freeInstruction(old[i]); getInstrPtr(mb,0)->gc |= GARBAGECONTROL; GDKfree(old); OPTDEBUGgarbageCollector{ int k; mnstr_printf(cntxt->fdout, "#Garbage collected BAT variables \n"); for ( k =0; k < vlimit; k++) mnstr_printf(cntxt->fdout,"%10s eolife %3d begin %3d lastupd %3d end %3d\n", getVarName(mb,k), mb->var[k]->eolife, getBeginLifespan(span,k), getLastUpdate(span,k), getEndLifespan(span,k)); mnstr_printf(cntxt->fdout, "End of GCoptimizer\n"); } GDKfree(span); return actions+1; }
int OPTrecyclerImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j, cnt, cand, actions = 1, marks = 0; InstrPtr *old, q,p; int limit; char *recycled; (void) cntxt; (void) stk; (void) pci; limit = mb->stop; old = mb->stmt; /* watch out, newly created instructions may introduce new variables */ recycled = GDKzalloc(sizeof(char) * mb->vtop * 2); if (recycled == NULL) return 0; if (newMalBlkStmt(mb, mb->ssize) < 0) { GDKfree(recycled); return 0; } pushInstruction(mb, old[0]); for (i = 1; i < limit; i++) { p = old[i]; if (p->token == ENDsymbol ) break; /* the first non-dataflow barrier breaks the recycler code*/ if (blockStart(p) && !(getFunctionId(p) && getFunctionId(p) == dataflowRef) ) break; if ( isUpdateInstruction(p) || hasSideEffects(p,TRUE)){ /* update instructions are not recycled but monitored*/ pushInstruction(mb, p); if (isUpdateInstruction(p)) { if (getModuleId(p) == batRef && isaBatType(getArgType(mb, p, 1))) { q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, getArg(p, 1)); actions++; } if (getModuleId(p) == sqlRef) { q= copyInstruction(p); getModuleId(q) = recycleRef; actions++; } } continue; } // Not all instruction may be recycled. In particular, we should avoid // MAL function with implicit/recursive side effects. // This can not always be detected easily. Likewise, we ignore cheap operations // Therefore, we use a safe subset to start with if ( ! (getModuleId(p) == sqlRef || getModuleId(p)== batRef || getModuleId(p) == algebraRef || getModuleId(p)==batcalcRef || getModuleId(p)== aggrRef || getModuleId(p)== groupRef || getModuleId(p)== batstrRef || getModuleId(p)== batmmathRef || getModuleId(p)== arrayRef || getModuleId(p)== batmtimeRef || getModuleId(p)== batcalcRef || getModuleId(p)== pcreRef || getModuleId(p)== mtimeRef || getModuleId(p) == calcRef || getModuleId(p)== dateRef || getModuleId(p) == timestampRef || getModuleId(p)== matRef ) ){ pushInstruction(mb,p); continue; } /* general rule: all arguments should be constants or recycled*/ cnt = 0; for (j = p->retc; j < p->argc; j++) if (recycled[getArg(p, j)] || isVarConstant(mb, getArg(p, j)) || isFunctionArgument(mb,getArg(p,j)) ) cnt++; cand = 0; for (j =0; j< p->retc; j++) if (recycled[getArg(p, j)] ==0) cand++; if (cnt == p->argc - p->retc && cand == p->retc) { marks++; p->recycle = RECYCLING; /* this instruction is to be monitored */ for (j = 0; j < p->retc; j++) recycled[getArg(p, j)] = 1; } pushInstruction(mb, p); } for (; i < limit; i++) pushInstruction(mb, old[i]); GDKfree(old); GDKfree(recycled); mb->recycle = marks > 0; OPTDEBUGrecycle { mnstr_printf(cntxt->fdout, "#recycle optimizer: "); printFunction(cntxt->fdout,mb, 0, LIST_MAL_ALL); } return actions + marks; }