LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_function.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 333 470 70.9 %
Date: 2024-04-25 20:03:45 Functions: 13 20 65.0 %

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

Generated by: LCOV version 1.14