LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_function.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 288 405 71.1 %
Date: 2021-09-14 22:17:06 Functions: 13 20 65.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * (author) M. Kersten
      11             :  * For documentation see website
      12             :  */
      13             : #include "monetdb_config.h"
      14             : #include "mal_function.h"
      15             : #include "mal_resolve.h"      /* for isPolymorphic() & chkProgram() */
      16             : #include "mal_interpreter.h"  /* for showErrors() */
      17             : #include "mal_listing.h"
      18             : #include "mal_namespace.h"
      19             : #include "mal_private.h"
      20             : 
      21       39722 : Symbol newFunctionArgs(const char *mod, const char *nme, int kind, int args)
      22             : {
      23             :         Symbol s;
      24             :         InstrPtr p;
      25             :         int varid;
      26             : 
      27       39722 :         if(mod == NULL || nme == NULL)
      28             :                 return NULL;
      29             : 
      30       39722 :         s = newSymbol(nme,kind);
      31       39722 :         if (s == NULL)
      32             :                 return NULL;
      33             : 
      34       39722 :         varid = newVariable(s->def,nme,strlen(nme),TYPE_any);
      35       39722 :         if( varid < 0){
      36           0 :                 freeSymbol(s);
      37           0 :                 return NULL;
      38             :         }
      39             : 
      40       39722 :         p = newInstructionArgs(NULL, mod, nme, args);
      41       39722 :         if (p == NULL) {
      42           0 :                 freeSymbol(s);
      43           0 :                 return NULL;
      44             :         }
      45       39722 :         p->token = kind;
      46       39722 :         p->barrier = 0;
      47       39722 :         setDestVar(p, varid);
      48       39722 :         pushInstruction(s->def,p);
      49       39722 :         return s;
      50             : }
      51             : 
      52       39133 : Symbol newFunction(const char *mod, const char *nme, int kind)
      53             : {
      54       39133 :         return newFunctionArgs(mod, nme, kind, MAXARG);
      55             : }
      56             : 
      57             : /*
      58             :  * Optimizers may be interested in the function definition
      59             :  * for obtaining properties. Rather than polution of the
      60             :  * instruction record with a scope reference, we use a lookup function until it
      61             :  * becomes a performance hindrance.
      62             :  */
      63           0 : Symbol  getFunctionSymbol(Module scope, InstrPtr p){
      64             :         Module m;
      65             :         Symbol s;
      66             : 
      67           0 :         for(m= findModule(scope,getModuleId(p)); m; m= m->link)
      68           0 :                 if(idcmp(m->name, getModuleId(p))==0 ) {
      69           0 :                         s= m->space[getSymbolIndex(getFunctionId(p))];
      70           0 :                         for(; s; s= s->peer)
      71           0 :                                 if( getSignature(s)->fcn == p->fcn)
      72           0 :                                         return s;
      73             :                 }
      74             :         return 0;
      75             : }
      76             : 
      77      130912 : int getPC(MalBlkPtr mb, InstrPtr p)
      78             : {   int i;
      79     1415788 :         for( i=0;i<mb->stop; i++)
      80     1415793 :         if( getInstrPtr(mb,i)==p) return i;
      81             :         return -1;
      82             : }
      83             : /*
      84             :  * Checking the control flow structure is done by a single pass over the
      85             :  * MAL program after the program has been type-checked.
      86             :  * It should inspect all BARRIER and CATCH blocks for proper structure.
      87             :  * If the flow is correct and not dependent on an undefined typed instruction
      88             :  * we avoid doing this check any further.
      89             :  */
      90             : #define DEPTH 128
      91             : 
      92             : str
      93     2189587 : chkFlow(MalBlkPtr mb)
      94             : {   int i,j,k, v,lastInstruction;
      95             :         int  pc[DEPTH];
      96             :         int  var[DEPTH];
      97             :         InstrPtr stmt[DEPTH];
      98             :         int btop=0;
      99             :         int endseen=0, retseen=0, yieldseen=0;
     100             :         InstrPtr p, sig;
     101             :         str msg = MAL_SUCCEED;
     102             : 
     103     2189587 :         if ( mb->errors != MAL_SUCCEED)
     104             :                 return mb->errors ;
     105     2189588 :         sig = getInstrPtr(mb, 0);
     106     2189588 :         lastInstruction = mb->stop-1;
     107   217104034 :         for(i= 0; i<mb->stop; i++){
     108   214914463 :                 p= getInstrPtr(mb,i);
     109             :                 /* we have to keep track on the maximal arguments/block
     110             :                   because it is needed by the interpreter */
     111   214914463 :                 switch( p->barrier){
     112      196075 :                 case BARRIERsymbol:
     113             :                 case CATCHsymbol:
     114      196075 :                         if(btop== DEPTH)
     115           0 :                             throw(MAL,"chkFlow", "%s.%s Too many nested MAL blocks", getModuleId(sig), getFunctionId(sig));
     116      196075 :                         pc[btop]= i;
     117      196075 :                         v= var[btop]= getDestVar(p);
     118      196075 :                         stmt[btop]=p;
     119             : 
     120      196821 :                         for(j=btop-1;j>=0;j--)
     121         746 :                         if( v==var[j])
     122           0 :                             throw(MAL,"chkFlow", "%s.%s recursive %s[%d] shields %s[%d]", getModuleId(sig), getFunctionId(sig), getVarName(mb,v), pc[j], getFcnName(mb),pc[i]);
     123             : 
     124      196075 :                         btop++;
     125      196075 :                         break;
     126      196072 :                 case EXITsymbol:
     127      196072 :                         v= getDestVar(p);
     128      196072 :                         if( btop>0 && var[btop-1] != v)
     129           3 :                             throw(MAL,"chkFlow",  "%s.%s exit-label '%s' doesnot match '%s'", getModuleId(sig), getFunctionId(sig), getVarName(mb,v), getVarName(mb,var[btop-1]));
     130      196069 :                         if(btop==0)
     131           4 :                             throw(MAL,"chkFlow", "%s.%s exit-label '%s' without begin-label",  getModuleId(sig), getFunctionId(sig), getVarName(mb,v));
     132             :                         /* search the matching block */
     133      196065 :                         for(j=btop-1;j>=0;j--)
     134      196065 :                         if( var[j]==v) break;
     135      196065 :                         if(j>=0) btop= j; else btop--;
     136             : 
     137             :                         /* retrofit LEAVE/REDO instructions */
     138      196065 :                         stmt[btop]->jump= i;
     139    33700532 :                         for(k=pc[btop]; k<i; k++){
     140    33504467 :                             InstrPtr p1= getInstrPtr(mb,k);
     141    33504467 :                             if( getDestVar(p1)==v ) {
     142             :                                 /* handle assignments with leave/redo option*/
     143      197388 :                                 if(p1->barrier== LEAVEsymbol )
     144          97 :                                     p1->jump= i;
     145      197388 :                                 if( p1->barrier==REDOsymbol )
     146        1218 :                                     p1->jump= pc[btop]+1;
     147             :                             }
     148             :                         }
     149             :                         break;
     150        1329 :                 case LEAVEsymbol:
     151             :                 case REDOsymbol:
     152        1329 :                         v= getDestVar(p);
     153        1338 :                         for(j=btop-1;j>=0;j--)
     154        1330 :                         if( var[j]==v) break;
     155        1329 :                         if(j<0){
     156           8 :                                 str nme=getVarName(mb,v);
     157           8 :                             throw(MAL,"chkFlow",  "%s.%s label '%s' not in guarded block", getModuleId(sig), getFunctionId(sig), nme);
     158             :                         }
     159             :                         break;
     160          13 :                 case YIELDsymbol:
     161          13 :                         { InstrPtr ps= getInstrPtr(mb,0);
     162          13 :                         if( ps->token != FACTORYsymbol){
     163           0 :                             throw(MAL,"chkFlow",  "%s.%s yield misplaced!",  getModuleId(sig), getFunctionId(sig));
     164             :                         }
     165             :                         yieldseen= TRUE;
     166             :                          }
     167             :                         /* fall through */
     168       25198 :                 case RETURNsymbol:
     169             :                         {
     170       25198 :                                 InstrPtr ps = getInstrPtr(mb, 0);
     171             :                                 int e;
     172       25198 :                                 if (p->barrier == RETURNsymbol)
     173             :                                         yieldseen = FALSE;    /* always end with a return */
     174       25198 :                                 if (ps->retc != p->retc) {
     175           2 :                                         throw(MAL,"chkFlow",  "%s.%s invalid return target!",  getModuleId(sig), getFunctionId(sig));
     176             :                                 } else
     177       25196 :                                 if (ps->typechk == TYPE_RESOLVED)
     178       52390 :                                         for (e = 0; e < p->retc; e++) {
     179       27211 :                                                 if (resolveType(getArgType(mb, ps, e), getArgType(mb, p, e)) < 0) {
     180           0 :                                                         str tpname = getTypeName(getArgType(mb, p, e));
     181           0 :                                                         msg = createException(MAL, "%s.%s %s type mismatch at type '%s'\n", getModuleId(p), getFunctionId(p),
     182           0 :                                                                         (p->barrier == RETURNsymbol ? "RETURN" : "YIELD"), tpname);
     183           0 :                                                         GDKfree(tpname);
     184           0 :                                                         return msg;
     185             :                                                 }
     186             :                                         }
     187             :                         }
     188             :                         //if (btop == 0)
     189             :                                 retseen = 1;
     190             :                         break;
     191             :             case RAISEsymbol:
     192             :                         endseen = 1;
     193             :                 break;
     194             :             case ENDsymbol:
     195             :                         endseen =1;
     196             :                 break;
     197   214495782 :                 default:
     198   214495782 :                         if( isaSignature(p) ){
     199    22492634 :                                 if( p->token == REMsymbol){
     200             :                                         /* do nothing */
     201     2189588 :                                 } else if( i) {
     202           0 :                                         str l = instruction2str(mb,0,p,TRUE);
     203           0 :                                         msg = createException( MAL, "%s.%s signature misplaced\n!%s", getModuleId(p), getFunctionId(p),l);
     204           0 :                                         GDKfree(l);
     205           0 :                                         return  msg;
     206             :                                 }
     207             :                         }
     208             :                 }
     209             :         }
     210             : 
     211     2189571 :         if(lastInstruction < mb->stop-1 )
     212           0 :                 throw(MAL,"chkFlow",  "%s.%s instructions after END", getModuleId(sig), getFunctionId(sig));
     213             : 
     214     2189571 :         if( endseen && btop  > 0)
     215           0 :                         throw(MAL,"chkFlow",  "barrier '%s' without exit in %s[%d]", getVarName(mb,var[btop - 1]), getFcnName(mb), i);
     216     2189571 :         p= getInstrPtr(mb,0);
     217     2189571 :         if( !isaSignature(p))
     218           0 :                 throw( MAL,"chkFlow",  "%s.%s signature missing",  getModuleId(sig), getFunctionId(sig));
     219     2189571 :         if( retseen == 0){
     220     2165400 :                 if( getArgType(mb,p,0)!= TYPE_void &&
     221          22 :                         (p->token==FUNCTIONsymbol || p->token==FACTORYsymbol))
     222           0 :                                 throw(MAL,"chkFlow",  "%s.%s RETURN missing", getModuleId(sig), getFunctionId(sig));
     223             :         }
     224     2189571 :         if ( yieldseen && getArgType(mb,p,0)!= TYPE_void)
     225           0 :                         throw( MAL,"chkFlow",  "%s.%s RETURN missing", getModuleId(sig), getFunctionId(sig));
     226             :         return MAL_SUCCEED;
     227             : }
     228             : 
     229             : /*
     230             :  * A code may contain temporary names for marking barrier blocks.
     231             :  * Since they are introduced by the compiler, the parser should locate
     232             :  * them itself when encountering the LEAVE,EXIT,REDO.
     233             :  * The starting position is mostly the last statement entered.
     234             :  * Purposely, the nameless envelops searches the name of the last
     235             :  * unclosed block. All others are ignored.
     236             :  */
     237           4 : int getBarrierEnvelop(MalBlkPtr mb){
     238             :         int pc;
     239             :         InstrPtr p;
     240          10 :         for(pc= mb->stop-2 ; pc>=0; pc--){
     241           9 :                 p= getInstrPtr(mb,pc);
     242           9 :                 if( blockExit(p)){
     243           1 :                         int l= p->argv[0];
     244           4 :                         for(; pc>=0;pc--){
     245           4 :                             p= getInstrPtr(mb,pc);
     246           4 :                             if( blockStart(p) && p->argv[0]==l) break;
     247             :                         }
     248           1 :                         continue;
     249             :                 }
     250           8 :                 if( blockStart(p) ) return p->argv[0];
     251             :         }
     252           1 :         return newTmpVariable(mb,TYPE_any);
     253             : }
     254             : 
     255          16 : static void replaceTypeVar(MalBlkPtr mb, InstrPtr p, int v, malType t){
     256             :         int j,i,x,y;
     257             : 
     258          89 :         for(j=0; j<mb->stop; j++){
     259          73 :             p= getInstrPtr(mb,j);
     260          73 :         if( p->polymorphic)
     261         100 :         for(i=0;i<p->argc; i++)
     262          72 :         if( isPolymorphic(x= getArgType(mb,p,i))) {
     263          64 :                 if( isaBatType(x)){
     264             :                         int tail;
     265             :                         int tx;
     266          20 :                         tail = getBatType(x);
     267          20 :                         tx = getTypeIndex(x);
     268          20 :                         if(v && tx == v && tail == TYPE_any){
     269             :                             tx= 0;
     270             :                             tail = t;
     271             :                         }
     272          20 :                         y= newBatType(tail);
     273          20 :                         setTypeIndex(y,tx);
     274          20 :                         setArgType(mb,p,i,y);
     275             :                 } else
     276          24 :                 if(getTypeIndex(x) == v){
     277          17 :                         setArgType(mb,p,i,t);
     278             :                 }
     279             :                 else {
     280             :                 }
     281             :         }
     282             :         }
     283          16 : }
     284             : 
     285             : /* insert a symbol into the symbol table just before the symbol
     286             :  * "before". */
     287             : static void
     288          56 : insertSymbolBefore(Module scope, Symbol prg, Symbol before)
     289             : {
     290             :         InstrPtr sig;
     291             :         int t;
     292             :         Symbol s;
     293             : 
     294          56 :         assert(strcmp(prg->name, before->name) == 0);
     295          56 :         sig = getSignature(prg);
     296          56 :         if (getModuleId(sig) && getModuleId(sig) != scope->name) {
     297           0 :                 Module c = findModule(scope, getModuleId(sig));
     298           0 :                 if (c)
     299             :                         scope = c;
     300             :         }
     301          56 :         t = getSymbolIndex(getFunctionId(sig));
     302          56 :         assert(scope->space != NULL);
     303          56 :         assert(scope->space[t] != NULL);
     304             :         s = scope->space[t];
     305          56 :         prg->skip = before->skip;
     306          56 :         prg->peer = before;
     307          56 :         if (s == before) {
     308          25 :                 scope->space[t] = prg;
     309             :         } else {
     310             :                 for (;;) {
     311          76 :                         assert(s != NULL);
     312          76 :                         if (s->skip == before) {
     313          29 :                                 s->skip = prg;
     314             :                         }
     315          76 :                         if (s->peer == before) {
     316          31 :                                 s->peer = prg;
     317          31 :                                 break;
     318             :                         }
     319             :                         s = s->peer;
     320             :                 }
     321             :         }
     322          56 : }
     323             : 
     324             : /*
     325             :  * Upon cloning a function we should remove all the polymorphic flags.
     326             :  * Otherwise we may end up with a recursive clone.
     327             :  */
     328             : Symbol
     329          56 : cloneFunction(Module scope, Symbol proc, MalBlkPtr mb, InstrPtr p)
     330             : {
     331             :         Symbol new;
     332             :         int i,v;
     333             :         InstrPtr pp;
     334             :         str msg = MAL_SUCCEED;
     335             : 
     336          56 :         new = newFunction(scope->name, proc->name, getSignature(proc)->token);
     337          56 :         if( new == NULL){
     338             :                 return NULL;
     339             :         }
     340          56 :         freeMalBlk(new->def);
     341          56 :         if((new->def = copyMalBlk(proc->def)) == NULL) {
     342           0 :                 freeSymbol(new);
     343           0 :                 return NULL;
     344             :         }
     345             :         /* now change the definition of the original proc */
     346             :         /* check for errors after fixation , TODO*/
     347          56 :         pp = getSignature(new);
     348         187 :         for (i = 0; i < pp->argc; i++)
     349         131 :                 if (isPolymorphic(v = getArgType(new->def,pp, i))) {
     350          15 :                         int t = getArgType(mb, p, i);
     351             : 
     352          15 :                         if (v == TYPE_any)
     353           1 :                                 replaceTypeVar(new->def, pp, v, t);
     354          15 :                         if (isaBatType(v)) {
     355          14 :                                 if (getTypeIndex(v))
     356          14 :                                         replaceTypeVar(new->def, pp, getTypeIndex(v), getBatType(t));
     357             :                         } else
     358           1 :                                 replaceTypeVar(new->def, pp, getTypeIndex(v), t);
     359             :                 }
     360             :         /* include the function at the proper place in the scope */
     361          56 :         insertSymbolBefore(scope, new, proc);
     362             :         /* clear polymorphic and type to force analysis*/
     363         344 :         for (i = 0; i < new->def->stop; i++) {
     364         288 :                 pp = getInstrPtr(new->def, i);
     365         288 :             pp->typechk = TYPE_UNKNOWN;
     366         288 :                 pp->polymorphic = 0;
     367             :         }
     368             :         /* clear type fixations */
     369         415 :         for (i = 0; i < new->def->vtop; i++)
     370         359 :                 clrVarFixed(new->def, i);
     371             : 
     372             : 
     373             :         /* check for errors after fixation , TODO*/
     374             :         /* beware, we should now ignore any cloning */
     375          56 :         if (proc->def->errors == 0) {
     376          56 :                 msg = chkProgram(scope,new->def);
     377          56 :                 if( msg)
     378           3 :                         mb->errors = msg;
     379             :                 else
     380          53 :                 if(new->def->errors){
     381           0 :                         assert(mb->errors == NULL);
     382           0 :                         mb->errors = new->def->errors;
     383           0 :                         mb->errors = createMalException(mb,0,TYPE,"Error in cloned function");
     384           0 :                         new->def->errors = 0;
     385             :                 }
     386             :         }
     387             : 
     388             :         return new;
     389             : }
     390             : 
     391             : /*
     392             :  * For commands we do not have to clone the routine. We merely have to
     393             :  * assure that the type-constraints are obeyed. The resulting type
     394             :  * is returned.
     395             :  */
     396             : void
     397           0 : debugFunction(stream *fd, MalBlkPtr mb, MalStkPtr stk, int flg, int first, int step)
     398             : {
     399             :         int i,j;
     400             :         str ps;
     401             :         InstrPtr p;
     402             : 
     403           0 :         if (mb == NULL) {
     404           0 :                 mnstr_printf(fd, "# function definition missing\n");
     405           0 :                 return;
     406             :         }
     407           0 :         if ( flg == 0 || step < 0  || first < 0 )
     408             :                 return;
     409             : 
     410           0 :         if( mb->errors)
     411           0 :                                 mnstr_printf(fd,"#errors seen: %s\n", mb->errors);
     412           0 :         for (i = first; i < first +step && i < mb->stop; i++){
     413           0 :                 ps = instruction2str(mb, stk, (p=getInstrPtr(mb, i)), flg);
     414           0 :                 if (ps) {
     415           0 :                         if (p->token == REMsymbol)
     416           0 :                                 mnstr_printf(fd,"%-40s\n",ps);
     417             :                         else {
     418           0 :                                 mnstr_printf(fd,"%-40s\t#[%d] %s ",ps, i, (p->blk? p->blk->binding:""));
     419           0 :                                 if( flg & LIST_MAL_FLOW){
     420           0 :                                         for(j =0; j < p->retc; j++)
     421           0 :                                                 mnstr_printf(fd,"%d ",getArg(p,j));
     422           0 :                                         if( p->argc - p->retc > 0)
     423           0 :                                                 mnstr_printf(fd,"<- ");
     424           0 :                                         for(; j < p->argc; j++)
     425           0 :                                                 mnstr_printf(fd,"%d ",getArg(p,j));
     426             :                                 }
     427           0 :                                 mnstr_printf(fd,"\n");
     428             :                         }
     429           0 :                         GDKfree(ps);
     430           0 :                 } else mnstr_printf(fd,"#failed instruction2str()\n");
     431             :         }
     432             : }
     433             : 
     434             : void
     435          69 : listFunction(stream *fd, MalBlkPtr mb, MalStkPtr stk, int flg, int first, int size)
     436             : {
     437             :         int i;
     438             :         int sample = 256;
     439             : 
     440          69 :         if (mb == NULL) {
     441           0 :                 mnstr_printf(fd, "# function definition missing\n");
     442           0 :                 return;
     443             :         }
     444          69 :         if ( flg == 0)
     445             :                 return;
     446             : 
     447          69 :         assert(size>=0);
     448          69 :         assert(first>=0 && first <mb->stop);
     449          69 :         renameVariables(mb);
     450          69 :         if (flg & LIST_MAL_MAPI) {
     451             :                 size_t len = 0;
     452             :                 str ps;
     453          62 :                 mnstr_printf(fd, "&1 0 %d 1 %d\n", /* type id rows columns tuples */
     454             :                                 mb->stop, mb->stop);
     455          62 :                 mnstr_printf(fd, "%% .explain # table_name\n");
     456          62 :                 mnstr_printf(fd, "%% mal # name\n");
     457          62 :                 mnstr_printf(fd, "%% clob # type\n");
     458        3030 :                 for (i = first; i < first +size && i < mb->stop && sample-- > 0; i++) {
     459        2968 :                         ps = instruction2str(mb, stk, getInstrPtr(mb, i), flg);
     460        2968 :                         if (ps) {
     461        2968 :                                 size_t l = strlen(ps);
     462             :                                 if (l > len)
     463             :                                         len = l;
     464        2968 :                                 GDKfree(ps);
     465           0 :                         } else mnstr_printf(fd,"#failed instruction2str()\n");
     466             :                 }
     467          62 :                 mnstr_printf(fd, "%% %zu # length\n", len);
     468             :         }
     469        3095 :         for (i = first; i < first +size && i < mb->stop; i++)
     470        3026 :                 printInstruction(fd, mb, stk, getInstrPtr(mb, i), flg);
     471             : }
     472             : 
     473             : 
     474             : void
     475          89 : renameVariables(MalBlkPtr mb)
     476             : {
     477             :         int i;
     478             :         char *s;
     479             : 
     480             :         /* Temporary variables get their name from the position in the symbol table */
     481             :         /* However, also MAL input may contain temporary names. At some point you need to clean it up to avoid clashes */
     482             :         /* Certainly when you are about to print the MAL function */
     483             :         /* During optimization they may be copied around, which means there name should be re-establised */
     484             :         /* rename all temporaries for ease of variable table interpretation */
     485             :         /* this code should not be necessary is variables always keep their position */
     486        7334 :         for( i = 0; i < mb->vtop; i++) {
     487        7245 :                 s = getVarName(mb, i);
     488        7245 :                 if( s[1] == '_' && (*s == 'C' || *s == 'X'))
     489        7143 :                         snprintf(s + 2, IDLENGTH-2, "%d", i);
     490             :         }
     491          89 : }
     492             : 
     493          69 : void printFunction(stream *fd, MalBlkPtr mb, MalStkPtr stk, int flg)
     494             : {
     495             :         int i,j;
     496             :         InstrPtr p;
     497             : 
     498             : 
     499             :         // Set the used bits properly
     500        6132 :         for(i=0; i< mb->vtop; i++)
     501        6063 :                 clrVarUsed(mb,i);
     502             : 
     503             : 
     504        3095 :         for(i=0; i< mb->stop; i++){
     505        3026 :                 p= getInstrPtr(mb,i);
     506        9887 :                 for(j= p->retc; j<p->argc; j++)
     507        6861 :                         setVarUsed(mb, getArg(p,j));
     508        3026 :                 if( p->barrier)
     509          24 :                         for(j= 0; j< p->retc; j++)
     510          12 :                                 setVarUsed(mb, getArg(p,j));
     511             :         }
     512          69 :         listFunction(fd,mb,stk,flg,0,mb->stop);
     513          69 : }
     514             : 
     515           0 : void traceFunction(component_t comp, MalBlkPtr mb, MalStkPtr stk, int flg)
     516             : {
     517             :         int i,j;
     518             :         InstrPtr p;
     519             :         // Set the used bits properly
     520           0 :         for(i=0; i< mb->vtop; i++)
     521           0 :                 clrVarUsed(mb,i);
     522           0 :         for(i=0; i< mb->stop; i++){
     523           0 :                 p= getInstrPtr(mb,i);
     524           0 :                 for(j= p->retc; j<p->argc; j++)
     525           0 :                         setVarUsed(mb, getArg(p,j));
     526           0 :                 if( p->barrier)
     527           0 :                         for(j= 0; j< p->retc; j++)
     528           0 :                                 setVarUsed(mb, getArg(p,j));
     529             :         }
     530           0 :         for (i = 0; i < mb->stop; i++)
     531           0 :                 traceInstruction(comp, mb, stk, getInstrPtr(mb, i), flg);
     532           0 : }
     533             : 
     534             : /* initialize the static scope boundaries for all variables */
     535             : void
     536     1777217 : setVariableScope(MalBlkPtr mb)
     537             : {
     538             :         int pc, k, depth=0, dflow= -1;
     539             :         InstrPtr p;
     540             : 
     541             :         /* reset the scope admin */
     542   280964637 :         for (k = 0; k < mb->vtop; k++)
     543   279187420 :         if( isVarConstant(mb,k)){
     544    67468276 :                 setVarScope(mb,k,0);
     545    67468276 :                 setVarDeclared(mb,k,0);
     546    67468276 :                 setVarUpdated(mb,k,0);
     547    67468276 :                 setVarEolife(mb,k,mb->stop);
     548             :         } else {
     549   211719144 :                 setVarScope(mb,k,0);
     550   211719144 :                 setVarDeclared(mb,k,0);
     551   211719144 :                 setVarUpdated(mb,k,0);
     552   211719144 :                 setVarEolife(mb,k,0);
     553             :         }
     554             : 
     555   145717694 :         for (pc = 0; pc < mb->stop; pc++) {
     556   143940477 :                 p = getInstrPtr(mb, pc);
     557   143940477 :                 if( p->token == NOOPsymbol)
     558           0 :                         continue;
     559             : 
     560   143940477 :                 if( blockStart(p)){
     561      375225 :                         if (getModuleId(p) && getFunctionId(p) && strcmp(getModuleId(p),"language")==0 && strcmp(getFunctionId(p),"dataflow")==0){
     562      371079 :                                 if( dflow != -1)
     563           0 :                                         addMalException(mb,"setLifeSpan nested dataflow blocks not allowed" );
     564             :                                 dflow= depth;
     565             :                         } else
     566        4146 :                                 depth++;
     567             :                 }
     568             : 
     569   668392242 :                 for (k = 0; k < p->argc; k++) {
     570   524451765 :                         int v = getArg(p,k);
     571   524451765 :                         if( isVarConstant(mb,v) && getVarUpdated(mb,v) == 0)
     572    60671986 :                                 setVarUpdated(mb,v, pc);
     573             : 
     574   524451765 :                         if ( getVarDeclared(mb,v) == 0 ){
     575   211603075 :                                 setVarDeclared(mb,v, pc);
     576   211603075 :                                 setVarScope(mb,v,depth);
     577             :                         }
     578   524451765 :                         if (k < p->retc )
     579   151314577 :                                 setVarUpdated(mb,v, pc);
     580   524451765 :                         if ( getVarScope(mb,v) == depth )
     581   524431264 :                                 setVarEolife(mb,v,pc);
     582             : 
     583   524451765 :                         if ( k >= p->retc && getVarScope(mb,v) < depth )
     584       16886 :                                 setVarEolife(mb,v,-1);
     585             :                 }
     586             :                 /*
     587             :                  * At a block exit we can finalize all variables defined within that block.
     588             :                  * This does not hold for dataflow blocks. They merely direct the execution
     589             :                  * thread, not the syntactic scope.
     590             :                  */
     591   143940477 :                 if( blockExit(p) ){
     592   155811206 :                         for (k = 0; k < mb->vtop; k++)
     593   155435982 :                         if ( getVarEolife(mb,k) == 0 && getVarScope(mb,k) ==depth )
     594    50858124 :                                 setVarEolife(mb,k,pc);
     595   104577858 :                         else if ( getVarEolife(mb,k) == -1 )
     596        8662 :                                 setVarEolife(mb,k,pc);
     597             : 
     598      375224 :                         if( dflow == depth)
     599             :                                 dflow= -1;
     600        4146 :                         else depth--;
     601             :                 }
     602   143940477 :                 if( blockReturn(p)){
     603        8178 :                         for (k = 0; k < p->argc; k++)
     604        6348 :                                 setVarEolife(mb,getArg(p,k),pc);
     605             :                 }
     606             :         }
     607   280965154 :         for (k = 0; k < mb->vtop; k++)
     608   279187937 :                 if( getVarEolife(mb,k) == 0)
     609    23177350 :                         setVarEolife(mb,k, mb->stop-1);
     610     1777217 : }
     611             : 
     612             : int
     613           0 : isLoopBarrier(MalBlkPtr mb, int pc){
     614             :         InstrPtr p;
     615             :         int varid;
     616           0 :         p= getInstrPtr(mb,pc);
     617           0 :         if( p->barrier != BARRIERsymbol)
     618             :                 return 0;
     619           0 :         varid= getDestVar(p);
     620           0 :         for(pc++; pc< mb->stop; pc++){
     621           0 :                 p= getInstrPtr(mb,pc);
     622           0 :                 if( p->barrier == REDOsymbol && getDestVar(p)== varid)
     623             :                         return 1;
     624           0 :                 if( p->barrier == EXITsymbol && getDestVar(p)== varid)
     625             :                         break;
     626             :         }
     627             :         return 0;
     628             : }
     629             : int
     630           0 : getBlockBegin(MalBlkPtr mb,int pc){
     631             :         InstrPtr p;
     632             :         int varid=0,i;
     633             : 
     634           0 :         for(i= pc; i< mb->stop; i++){
     635           0 :                 p= getInstrPtr(mb,i);
     636           0 :                 if( p->barrier == EXITsymbol ){
     637           0 :                         varid= getDestVar(p);
     638           0 :                         break;
     639             :                 }
     640             :         }
     641           0 :         if( i==mb->stop) return 0;
     642             : 
     643           0 :         for(; pc> 0; pc--){
     644           0 :                 p= getInstrPtr(mb,pc);
     645           0 :                 if( (p->barrier == BARRIERsymbol || p->barrier == CATCHsymbol) &&
     646           0 :                     getDestVar(p)== varid)
     647           0 :                         return pc;
     648             :         }
     649             :         return 0;
     650             : }
     651             : int
     652           0 : getBlockExit(MalBlkPtr mb,int pc){
     653             :         InstrPtr p;
     654             :         int varid;
     655           0 :         p= getInstrPtr(mb,pc);
     656           0 :         if( p->barrier != BARRIERsymbol && p->barrier != CATCHsymbol)
     657             :                 return 0;
     658           0 :         varid= getDestVar(p);
     659           0 :         for(pc++; pc< mb->stop; pc++){
     660           0 :                 p= getInstrPtr(mb,pc);
     661           0 :                 if( p->barrier == EXITsymbol && getDestVar(p)== varid)
     662           0 :                         return pc;
     663             :         }
     664             :         return 0;
     665             : }
     666             : /*
     667             :  * Variable declaration
     668             :  * Variables are implicitly declared upon first use.
     669             :  * This feature may become a source of runtime errors and
     670             :  * complicates the analyse during optimization.
     671             :  * Therefore, in line with the flow of control check,
     672             :  * we make sure that all variables are properly initialized
     673             :  * before being used. Since barrier blocks may be skipped at
     674             :  * runtime, they actually introduce a separate scope.
     675             :  * Variables declared within a block may not be used outside it.
     676             :  * Variables can only be declared once.
     677             :  *
     678             :  * In many situation chkFlow and chkDeclarations should be called
     679             :  * together. Moreover, an erroneous chkFlow most likely implies
     680             :  * errors in the declarations as well.
     681             :  *
     682             :  * Since in interactive mode each statement is handled separately,
     683             :  * we have to remember the scope assigned to a variable.
     684             :  */
     685           0 : void clrDeclarations(MalBlkPtr mb){
     686             :         int i;
     687           0 :         for(i=0;i<mb->vtop; i++){
     688           0 :                 clrVarInit(mb,i);
     689           0 :                 clrVarUsed(mb,i);
     690           0 :                 clrVarDisabled(mb,i);
     691             :         }
     692           0 : }
     693             : 
     694             : str
     695     2189572 : chkDeclarations(MalBlkPtr mb){
     696             :         int pc,i, k,l;
     697             :         InstrPtr p, sig;
     698             :         short blks[MAXDEPTH], top= 0, blkId=1;
     699             :         int dflow = -1;
     700             :         str msg = MAL_SUCCEED;
     701             : 
     702     2189572 :         if( mb->errors)
     703           0 :                 return GDKstrdup(mb->errors);
     704     2189572 :         blks[top] = blkId;
     705             : 
     706             :         /* initialize the scope */
     707   411942897 :         for(i=0; i< mb->vtop; i++)
     708   409753325 :                 setVarScope(mb,i,0);
     709             : 
     710             :         /* all signature variables are declared at outer level */
     711     2189572 :         sig= getInstrPtr(mb,0);
     712     4420582 :         for(k=0; k<sig->argc; k++)
     713     2231010 :                 setVarScope(mb, getArg(sig, k), blkId);
     714             : 
     715   214914254 :         for(pc=1;pc<mb->stop; pc++){
     716   212724688 :                 p= getInstrPtr(mb,pc);
     717   212724688 :                 if ( p->token == REMsymbol || p->token == NOOPsymbol)
     718    20303083 :                         continue;
     719             :                 /* check correct use of the arguments*/
     720   797413784 :                 for(k=p->retc;k<p->argc; k++) {
     721   604992185 :                         l=getArg(p,k);
     722   604992185 :                         if ( l < 0)
     723           0 :                                         throw(MAL,"chkFlow",  "%s.%s Non-declared variable: pc=%d, var= %d",  getModuleId(sig), getFunctionId(sig), pc, k);
     724   604992185 :                         setVarUsed(mb,l);
     725   604992185 :                         if( getVarScope(mb,l) == 0){
     726             :                                 /*
     727             :                                  * The problem created here is that only variables are
     728             :                                  * recognized that are declared through instructions.
     729             :                                  * For interactive code, and code that is based on a global
     730             :                                  * stack this is insufficient. In those cases, the variable
     731             :                                  * can be defined in a previous execution.
     732             :                                  * We have to recognize if the declaration takes place
     733             :                                  * in the context of a global stack.
     734             :                                  */
     735   237125219 :                                 if( p->barrier == CATCHsymbol){
     736           0 :                                         setVarScope(mb, l, blks[0]);
     737   237125219 :                                 } else if( !( isVarConstant(mb, l) || isVarTypedef(mb,l)) && !isVarInit(mb,l) ) {
     738           6 :                                         throw(MAL,"chkFlow",  "%s.%s '%s' may not be used before being initialized",  getModuleId(sig), getFunctionId(sig), getVarName(mb,l));
     739             :                                 }
     740   367866966 :                         } else if( !isVarInit(mb,l) ){
     741             :                             /* is the block still active ? */
     742       40915 :                             for( i=0; i<= top; i++)
     743       40915 :                                 if( blks[i] == getVarScope(mb,l) )
     744             :                                         break;
     745       40915 :                             if( i> top || blks[i]!= getVarScope(mb,l) )
     746           0 :                                 throw( MAL,"chkFlow",  "%s.%s '%s' used outside scope", getModuleId(sig), getFunctionId(sig), getVarName(mb,l));
     747             :                         }
     748   604992179 :                         if( blockCntrl(p) || blockStart(p) )
     749       33268 :                                 setVarInit(mb, l);
     750             :                 }
     751             :                 /* define variables */
     752   400605582 :                 for(k=0; k<p->retc; k++){
     753   208183983 :                         l= getArg(p,k);
     754   208183983 :                         if (isVarInit(mb, l) && getVarScope(mb,l) == 0) {
     755             :                                 /* first time we see this variable and it is already
     756             :                                  * initialized: assume it exists globally */
     757   174991663 :                                 setVarScope(mb, l, blks[0]);
     758             :                         }
     759   208183983 :                         setVarInit(mb,l);
     760   208183983 :                         if( getVarScope(mb,l) == 0){
     761             :                                 /* variable has not been defined yet */
     762             :                                 /* exceptions are always declared at level 1 */
     763    32958044 :                                 if( p->barrier == CATCHsymbol)
     764         150 :                                         setVarScope(mb, l, blks[0]);
     765             :                                 else
     766    32957894 :                                         setVarScope(mb, l, blks[top]);
     767             :                         }
     768   208183983 :                         if( blockCntrl(p) || blockStart(p) )
     769      226709 :                                 setVarUsed(mb, l);
     770             :                 }
     771   192421599 :                 if( p->barrier && msg == MAL_SUCCEED){
     772      418612 :                         if ( blockStart(p)){
     773      196051 :                                 if( top == MAXDEPTH-2)
     774           0 :                                         throw(MAL,"chkFlow",  "%s.%s too deeply nested  MAL program",  getModuleId(sig), getFunctionId(sig));
     775      196051 :                                 blkId++;
     776      196051 :                                 if (getModuleId(p) && getFunctionId(p) && strcmp(getModuleId(p),"language")==0 && strcmp(getFunctionId(p),"dataflow")== 0){
     777      191055 :                                         if( dflow != -1)
     778           0 :                                                 throw(MAL,"chkFlow",  "%s.%s setLifeSpan nested dataflow blocks not allowed", getModuleId(sig), getFunctionId(sig));
     779      191055 :                                         dflow= blkId;
     780             :                                 }
     781      196051 :                                 blks[++top]= blkId;
     782             :                         }
     783      418612 :                         if( blockExit(p) && top > 0 ){
     784      196051 :                                 if( dflow == blkId){
     785             :                                         dflow = -1;
     786             :                                 } else
     787             :                                 /*
     788             :                                  * At the end of the block we should reset the status of all variables
     789             :                                  * defined within the block. For, the block could have been skipped
     790             :                                  * leading to uninitialized variables.
     791             :                                  */
     792     3281880 :                                 for (l = 0; l < mb->vtop; l++)
     793     3276884 :                                 if( getVarScope(mb,l) == blks[top]){
     794       34382 :                                         setVarScope(mb,l, 0);
     795       34382 :                                         clrVarInit(mb,l);
     796             :                                 }
     797      196051 :                             top--;
     798             :                         }
     799             :                 }
     800             :         }
     801             :         return msg;
     802             : }

Generated by: LCOV version 1.14