LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_function.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 309 436 70.9 %
Date: 2024-10-07 21:21:43 Functions: 12 18 66.7 %

          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       50427 : newFunctionArgs(const char *mod, const char *nme, int kind, int args)
      27             : {
      28       50427 :         Symbol s;
      29             : 
      30       50427 :         if (mod == NULL || nme == NULL)
      31             :                 return NULL;
      32             : 
      33       50427 :         s = newSymbol(nme, kind);
      34       50430 :         if (s == NULL)
      35             :                 return NULL;
      36             : 
      37       50430 :         if (kind == FUNCTIONsymbol) {
      38       50415 :                 int varid = newVariable(s->def, nme, strlen(nme), TYPE_any);
      39       50408 :                 if (varid < 0) {
      40           0 :                         freeSymbol(s);
      41           0 :                         return NULL;
      42             :                 }
      43             : 
      44       50408 :                 if (args > 0) {
      45       50397 :                         InstrPtr p = newInstructionArgs(NULL, mod, nme, args);
      46       50398 :                         if (p == NULL) {
      47           0 :                                 freeSymbol(s);
      48           0 :                                 return NULL;
      49             :                         }
      50       50398 :                         p->token = kind;
      51       50398 :                         p->barrier = 0;
      52       50398 :                         setDestVar(p, varid);
      53       50398 :                         pushInstruction(s->def, p);
      54       50393 :                         if (s->def->errors) {
      55           0 :                                 freeSymbol(s);
      56           0 :                                 return NULL;
      57             :                         }
      58             :                 }
      59             :         }
      60             :         return s;
      61             : }
      62             : 
      63             : Symbol
      64       49210 : newFunction(const char *mod, const char *nme, int kind)
      65             : {
      66       49210 :         return newFunctionArgs(mod, nme, kind, MAXARG);
      67             : }
      68             : 
      69             : int
      70      168786 : getPC(MalBlkPtr mb, InstrPtr p)
      71             : {
      72      168786 :         int i;
      73     1930091 :         for (i = 0; i < mb->stop; i++)
      74     1930103 :                 if (getInstrPtr(mb, i) == p)
      75      168798 :                         return i;
      76             :         return -1;
      77             : }
      78             : 
      79             : /*
      80             :  * Checking the control flow structure is done by a single pass over the
      81             :  * MAL program after the program has been type-checked.
      82             :  * It should inspect all BARRIER and CATCH blocks for proper structure.
      83             :  * If the flow is correct and not dependent on an undefined typed instruction
      84             :  * we avoid doing this check any further.
      85             :  */
      86             : #define DEPTH 128
      87             : 
      88             : str
      89     3239622 : chkFlow(MalBlkPtr mb)
      90             : {
      91     3239622 :         int i, j, k, v, lastInstruction;
      92     3239622 :         int pc[DEPTH];
      93     3239622 :         int var[DEPTH];
      94     3239622 :         InstrPtr stmt[DEPTH];
      95     3239622 :         int btop = 0;
      96     3239622 :         int endseen = 0, retseen = 0;
      97     3239622 :         InstrPtr p, sig;
      98     3239622 :         str msg = MAL_SUCCEED;
      99     3239622 :         char name[IDLENGTH] = { 0 };
     100             : 
     101     3239622 :         if (mb->errors != MAL_SUCCEED)
     102             :                 return mb->errors;
     103     3240986 :         sig = getInstrPtr(mb, 0);
     104     3240986 :         lastInstruction = mb->stop - 1;
     105   209569074 :         for (i = 0; i < mb->stop; i++) {
     106   206328102 :                 p = getInstrPtr(mb, i);
     107             :                 /* we have to keep track on the maximal arguments/block
     108             :                    because it is needed by the interpreter */
     109   206328102 :                 switch (p->barrier) {
     110      267525 :                 case BARRIERsymbol:
     111             :                 case CATCHsymbol:
     112      267525 :                         if (btop == DEPTH)
     113           0 :                                 throw(MAL, "chkFlow", "%s.%s Too many nested MAL blocks",
     114             :                                           getModuleId(sig), getFunctionId(sig));
     115      267525 :                         pc[btop] = i;
     116      267525 :                         v = var[btop] = getDestVar(p);
     117      267525 :                         stmt[btop] = p;
     118             : 
     119      268278 :                         for (j = btop - 1; j >= 0; j--)
     120         753 :                                 if (v == var[j])
     121           0 :                                         throw(MAL, "chkFlow",
     122             :                                                   "%s.%s recursive %s[%d] shields %s[%d]",
     123             :                                                   getModuleId(sig), getFunctionId(sig), getVarNameIntoBuffer(mb, v, name),
     124           0 :                                                   pc[j], getFcnName(mb), pc[i]);
     125             : 
     126      267525 :                         btop++;
     127      267525 :                         break;
     128      267683 :                 case EXITsymbol:
     129      267683 :                         v = getDestVar(p);
     130      267683 :                         if (btop > 0 && var[btop - 1] != v)
     131           3 :                                 throw(MAL, "chkFlow",
     132             :                                           "%s.%s exit-label '%s' does not match '%s'",
     133             :                                           getModuleId(sig), getFunctionId(sig), getVarNameIntoBuffer(mb, v, name),
     134             :                                           getVarNameIntoBuffer(mb, var[btop - 1], name));
     135      267680 :                         if (btop == 0)
     136           0 :                                 throw(MAL, "chkFlow",
     137             :                                           "%s.%s exit-label '%s' without begin-label",
     138             :                                           getModuleId(sig), getFunctionId(sig), getVarNameIntoBuffer(mb, v, name));
     139             :                         /* search the matching block */
     140      267680 :                         for (j = btop - 1; j >= 0; j--)
     141      267642 :                                 if (var[j] == v)
     142             :                                         break;
     143      267680 :                         if (j >= 0)
     144             :                                 btop = j;
     145             :                         else
     146           0 :                                 btop--;
     147             : 
     148             :                         /* retrofit LEAVE/REDO instructions */
     149      267680 :                         stmt[btop]->jump = i;
     150    25126981 :                         for (k = pc[btop]; k < i; k++) {
     151    24859301 :                                 InstrPtr p1 = getInstrPtr(mb, k);
     152    24859301 :                                 if (getDestVar(p1) == v) {
     153             :                                         /* handle assignments with leave/redo option */
     154      275530 :                                         if (p1->barrier == LEAVEsymbol)
     155         109 :                                                 p1->jump = i;
     156      275530 :                                         if (p1->barrier == REDOsymbol)
     157        8023 :                                                 p1->jump = pc[btop] + 1;
     158             :                                 }
     159             :                         }
     160             :                         break;
     161        8146 :                 case LEAVEsymbol:
     162             :                 case REDOsymbol:
     163        8146 :                         v = getDestVar(p);
     164        8155 :                         for (j = btop - 1; j >= 0; j--)
     165        8147 :                                 if (var[j] == v)
     166             :                                         break;
     167             :                         if (j < 0) {
     168           8 :                                 str nme = getVarNameIntoBuffer(mb, v, name);
     169           8 :                                 throw(MAL, "chkFlow", "%s.%s label '%s' not in guarded block",
     170             :                                           getModuleId(sig), getFunctionId(sig), nme);
     171             :                         }
     172             :                         break;
     173        3571 :                 case RETURNsymbol: {
     174        3571 :                         InstrPtr ps = getInstrPtr(mb, 0);
     175        3571 :                         int e;
     176        3571 :                         if (ps->retc != p->retc) {
     177           2 :                                 throw(MAL, "chkFlow", "%s.%s invalid return target!",
     178             :                                           getModuleId(sig), getFunctionId(sig));
     179        3569 :                         } else if (ps->typeresolved)
     180       21711 :                                 for (e = 0; e < p->retc; e++) {
     181       18151 :                                         if (resolvedType(getArgType(mb, ps, e), getArgType(mb, p, e)) < 0) {
     182           0 :                                                 str tpname = getTypeName(getArgType(mb, p, e));
     183           0 :                                                 msg = createException(MAL,
     184             :                                                                                           "%s.%s RETURN type mismatch at type '%s'\n",
     185           0 :                                                                                           getModuleId(p) ? getModuleId(p) :
     186             :                                                                                           "",
     187           0 :                                                                                           getFunctionId(p) ?
     188             :                                                                                           getFunctionId(p) : "", tpname);
     189           0 :                                                 GDKfree(tpname);
     190           0 :                                                 return msg;
     191             :                                         }
     192             :                                 }
     193             :                         //if (btop == 0)
     194             :                         retseen = 1;
     195             :                         break;
     196             :                 }
     197             :                 case RAISEsymbol:
     198             :                         endseen = 1;
     199             :                         break;
     200             :                 case ENDsymbol:
     201             :                         endseen = 1;
     202             :                         break;
     203   205780542 :                 default:
     204   205780542 :                         if (isaSignature(p)) {
     205    29431986 :                                 if (p->token == REMsymbol) {
     206             :                                         /* do nothing */
     207     3238949 :                                 } else if (i) {
     208           0 :                                         str l = instruction2str(mb, 0, p, TRUE);
     209           0 :                                         msg = createException(MAL, "%s.%s signature misplaced\n!%s",
     210             :                                                                                   getModuleId(p), getFunctionId(p), l);
     211           0 :                                         GDKfree(l);
     212           0 :                                         return msg;
     213             :                                 }
     214             :                         }
     215             :                 }
     216             :         }
     217             : 
     218     3240972 :         if (lastInstruction < mb->stop - 1)
     219           0 :                 throw(MAL, "chkFlow", "%s.%s instructions after END", getModuleId(sig),
     220             :                           getFunctionId(sig));
     221             : 
     222     3240972 :         if (endseen && btop > 0)
     223           0 :                 throw(MAL, "chkFlow", "barrier '%s' without exit in %s[%d]",
     224           0 :                           getVarNameIntoBuffer(mb, var[btop - 1], name), getFcnName(mb), i);
     225     3240972 :         p = getInstrPtr(mb, 0);
     226     3240972 :         if (!isaSignature(p))
     227           0 :                 throw(MAL, "chkFlow", "%s.%s signature missing", getModuleId(sig),
     228             :                           getFunctionId(sig));
     229     3240972 :         if (retseen == 0) {
     230     3238405 :                 if (getArgType(mb, p, 0) != TYPE_void && (p->token == FUNCTIONsymbol))
     231           0 :                         throw(MAL, "chkFlow", "%s.%s RETURN missing", getModuleId(sig),
     232             :                                   getFunctionId(sig));
     233             :         }
     234             :         return MAL_SUCCEED;
     235             : }
     236             : 
     237             : /*
     238             :  * A code may contain temporary names for marking barrier blocks.
     239             :  * Since they are introduced by the compiler, the parser should locate
     240             :  * them itself when encountering the LEAVE,EXIT,REDO.
     241             :  * The starting position is mostly the last statement entered.
     242             :  * Purposely, the nameless envelops searches the name of the last
     243             :  * unclosed block. All others are ignored.
     244             :  */
     245             : int
     246           4 : getBarrierEnvelop(MalBlkPtr mb)
     247             : {
     248           4 :         int pc;
     249           4 :         InstrPtr p;
     250          10 :         for (pc = mb->stop - 2; pc >= 0; pc--) {
     251           9 :                 p = getInstrPtr(mb, pc);
     252           9 :                 if (blockExit(p)) {
     253           1 :                         int l = p->argv[0];
     254           4 :                         for (; pc >= 0; pc--) {
     255           4 :                                 p = getInstrPtr(mb, pc);
     256           4 :                                 if (blockStart(p) && p->argv[0] == l)
     257             :                                         break;
     258             :                         }
     259           1 :                         continue;
     260             :                 }
     261           8 :                 if (blockStart(p))
     262           3 :                         return p->argv[0];
     263             :         }
     264           1 :         return newTmpVariable(mb, TYPE_any);
     265             : }
     266             : 
     267             : static void
     268          14 : replaceTypeVar(MalBlkPtr mb, InstrPtr p, int v, malType t)
     269             : {
     270          83 :         for (int j = 0; j < mb->stop; j++) {
     271          69 :                 p = getInstrPtr(mb, j);
     272          69 :                 if (p->polymorphic) {
     273          94 :                         for (int i = 0; i < p->argc; i++) {
     274          68 :                                 int x = getArgType(mb, p, i);
     275          68 :                                 if (isPolymorphic(x) && getTypeIndex(x) == v) {
     276          33 :                                         if (isaBatType(x)) {
     277          17 :                                                 int tail = newBatType(t);
     278          17 :                                                 setArgType(mb, p, i, tail);
     279             :                                         } else {
     280          16 :                                                 setArgType(mb, p, i, t);
     281             :                                         }
     282             :                                 }
     283             :                         }
     284             :                 }
     285             :         }
     286          14 : }
     287             : 
     288             : /* insert a symbol into the symbol table just before the symbol
     289             :  * "before". */
     290             : static void
     291          11 : insertSymbolBefore(Module scope, Symbol prg, Symbol before)
     292             : {
     293          11 :         int t;
     294          11 :         Symbol s;
     295             : 
     296          11 :         assert(strcmp(prg->name, before->name) == 0);
     297          11 :         t = getSymbolIndex(prg->name);
     298          11 :         assert(scope->space != NULL);
     299          11 :         assert(scope->space[t] != NULL);
     300          11 :         s = scope->space[t];
     301          11 :         prg->skip = before->skip;
     302          11 :         prg->peer = before;
     303          11 :         if (s == before) {
     304           9 :                 scope->space[t] = prg;
     305             :         } else {
     306           3 :                 for (;;) {
     307           3 :                         assert(s != NULL);
     308           3 :                         if (s->skip == before) {
     309           0 :                                 s->skip = prg;
     310             :                         }
     311           3 :                         if (s->peer == before) {
     312           2 :                                 s->peer = prg;
     313           2 :                                 break;
     314             :                         }
     315             :                         s = s->peer;
     316             :                 }
     317             :         }
     318          11 : }
     319             : 
     320             : /*
     321             :  * Upon cloning a function we should remove all the polymorphic flags.
     322             :  * Otherwise we may end up with a recursive clone.
     323             :  */
     324             : Symbol
     325          11 : cloneFunction(Module scope, Symbol proc, MalBlkPtr mb, InstrPtr p)
     326             : {
     327          11 :         Symbol new;
     328          11 :         int i, v;
     329          11 :         InstrPtr pp;
     330          11 :         str msg = MAL_SUCCEED;
     331             : 
     332          11 :         new = newFunctionArgs(scope->name, proc->name, proc->kind, -1);
     333          11 :         if (new == NULL) {
     334             :                 return NULL;
     335             :         }
     336          11 :         freeMalBlk(new->def);
     337          11 :         if ((new->def = copyMalBlk(proc->def)) == NULL) {
     338           0 :                 freeSymbol(new);
     339           0 :                 return NULL;
     340             :         }
     341             :         /* now change the definition of the original proc */
     342             :         /* check for errors after fixation , TODO */
     343          11 :         pp = getSignature(new);
     344          43 :         for (i = 0; i < pp->argc; i++)
     345          32 :                 if (isPolymorphic(v = getArgType(new->def, pp, i))) {
     346          14 :                         int t = getArgType(mb, p, i);
     347             : 
     348          14 :                         if (v == TYPE_any) {
     349             :                                 assert(0);
     350             :                                 replaceTypeVar(new->def, pp, v, t);
     351             :                         }
     352          14 :                         if (isaBatType(v)) {
     353          14 :                                 if (getTypeIndex(v))
     354          14 :                                         replaceTypeVar(new->def, pp, getTypeIndex(v), getBatType(t));
     355             :                         } else
     356           0 :                                 replaceTypeVar(new->def, pp, getTypeIndex(v), t);
     357             :                 }
     358             :         /* include the function at the proper place in the scope */
     359          11 :         insertSymbolBefore(scope, new, proc);
     360             :         /* clear polymorphic and type to force analysis */
     361          76 :         for (i = 0; i < new->def->stop; i++) {
     362          54 :                 pp = getInstrPtr(new->def, i);
     363          54 :                 pp->typeresolved = false;
     364          54 :                 pp->polymorphic = 0;
     365             :         }
     366             :         /* clear type fixations */
     367          85 :         for (i = 0; i < new->def->vtop; i++)
     368          74 :                 clrVarFixed(new->def, i);
     369             : 
     370             : 
     371             :         /* check for errors after fixation , TODO */
     372             :         /* beware, we should now ignore any cloning */
     373          11 :         if (proc->def->errors == 0) {
     374          11 :                 msg = chkProgram(scope, new->def);
     375          11 :                 if (msg)
     376           3 :                         mb->errors = msg;
     377           8 :                 else if (new->def->errors) {
     378           0 :                         assert(mb->errors == NULL);
     379           0 :                         mb->errors = new->def->errors;
     380           0 :                         mb->errors = createMalException(mb, 0, TYPE, "Error in cloned function");
     381           0 :                         new->def->errors = 0;
     382             :                 }
     383             :         }
     384             : 
     385             :         return new;
     386             : }
     387             : 
     388             : /*
     389             :  * For commands we do not have to clone the routine. We merely have to
     390             :  * assure that the type-constraints are obeyed. The resulting type
     391             :  * is returned.
     392             :  */
     393             : void
     394           0 : debugFunction(stream *fd, MalBlkPtr mb, MalStkPtr stk, int flg, int first,
     395             :                           int step)
     396             : {
     397           0 :         int i, j;
     398           0 :         str ps;
     399           0 :         InstrPtr p;
     400             : 
     401           0 :         if (mb == NULL) {
     402           0 :                 mnstr_printf(fd, "# function definition missing\n");
     403           0 :                 return;
     404             :         }
     405           0 :         if (flg == 0 || step < 0 || first < 0)
     406             :                 return;
     407             : 
     408           0 :         if (mb->errors)
     409           0 :                 mnstr_printf(fd, "#errors seen: %s\n", mb->errors);
     410           0 :         for (i = first; i < first + step && i < mb->stop; i++) {
     411           0 :                 ps = instruction2str(mb, stk, (p = getInstrPtr(mb, i)), flg);
     412           0 :                 if (ps) {
     413           0 :                         if (p->token == REMsymbol)
     414           0 :                                 mnstr_printf(fd, "%-40s\n", ps);
     415             :                         else {
     416           0 :                                 mnstr_printf(fd, "%-40s\t#[%d] %s ", ps, i,
     417           0 :                                                          (p->blk ? p->blk->binding : ""));
     418           0 :                                 if (flg & LIST_MAL_FLOW) {
     419           0 :                                         for (j = 0; j < p->retc; j++)
     420           0 :                                                 mnstr_printf(fd, "%d ", getArg(p, j));
     421           0 :                                         if (p->argc - p->retc > 0)
     422           0 :                                                 mnstr_printf(fd, "<- ");
     423           0 :                                         for (; j < p->argc; j++)
     424           0 :                                                 mnstr_printf(fd, "%d ", getArg(p, j));
     425             :                                 }
     426           0 :                                 mnstr_printf(fd, "\n");
     427             :                         }
     428           0 :                         GDKfree(ps);
     429             :                 } else
     430           0 :                         mnstr_printf(fd, "#failed instruction2str()\n");
     431             :         }
     432             : }
     433             : 
     434             : void
     435          69 : listFunction(stream *fd, MalBlkPtr mb, MalStkPtr stk, int flg, int first,
     436             :                          int size)
     437             : {
     438          69 :         int i;
     439          69 :         int sample = 256;
     440             : 
     441          69 :         if (mb == NULL) {
     442           0 :                 mnstr_printf(fd, "# function definition missing\n");
     443           0 :                 return;
     444             :         }
     445          69 :         if (flg == 0)
     446             :                 return;
     447             : 
     448          69 :         assert(size >= 0);
     449          69 :         assert(first >= 0 && first < mb->stop);
     450          69 :         if (flg & LIST_MAL_MAPI) {
     451          65 :                 size_t len = 0;
     452          65 :                 str ps;
     453          65 :                 mnstr_printf(fd, "&1 0 %d 1 %d\n",        /* type id rows columns tuples */
     454             :                                          mb->stop, mb->stop);
     455          65 :                 mnstr_printf(fd, "%% .explain # table_name\n");
     456          65 :                 mnstr_printf(fd, "%% mal # name\n");
     457          65 :                 mnstr_printf(fd, "%% clob # type\n");
     458        3144 :                 for (i = first; i < first + size && i < mb->stop && sample-- > 0; i++) {
     459        3014 :                         ps = instruction2str(mb, stk, getInstrPtr(mb, i), flg);
     460        3014 :                         if (ps) {
     461        3014 :                                 size_t l = strlen(ps);
     462        3014 :                                 if (l > len)
     463             :                                         len = l;
     464        3014 :                                 GDKfree(ps);
     465             :                         } else
     466           0 :                                 mnstr_printf(fd, "#failed instruction2str()\n");
     467             :                 }
     468          65 :                 mnstr_printf(fd, "%% %zu # length\n", len);
     469             :         }
     470        3123 :         for (i = first; i < first + size && i < mb->stop; i++)
     471        3054 :                 printInstruction(fd, mb, stk, getInstrPtr(mb, i), flg);
     472             : }
     473             : 
     474             : 
     475             : void
     476          69 : printFunction(stream *fd, MalBlkPtr mb, MalStkPtr stk, int flg)
     477             : {
     478          69 :         int i, j;
     479          69 :         InstrPtr p;
     480             : 
     481             : 
     482             :         // Set the used bits properly
     483        6549 :         for (i = 0; i < mb->vtop; i++)
     484        6480 :                 clrVarUsed(mb, i);
     485             : 
     486             : 
     487        3123 :         for (i = 0; i < mb->stop; i++) {
     488        3054 :                 p = getInstrPtr(mb, i);
     489        9905 :                 for (j = p->retc; j < p->argc; j++)
     490        6851 :                         setVarUsed(mb, getArg(p, j));
     491        3054 :                 if (p->barrier)
     492          24 :                         for (j = 0; j < p->retc; j++)
     493          12 :                                 setVarUsed(mb, getArg(p, j));
     494             :         }
     495          69 :         listFunction(fd, mb, stk, flg, 0, mb->stop);
     496          69 : }
     497             : 
     498             : void
     499           0 : traceFunction(component_t comp, MalBlkPtr mb, MalStkPtr stk, int flg)
     500             : {
     501           0 :         int i, j;
     502           0 :         InstrPtr p;
     503             :         // Set the used bits properly
     504           0 :         for (i = 0; i < mb->vtop; i++)
     505           0 :                 clrVarUsed(mb, i);
     506           0 :         for (i = 0; i < mb->stop; i++) {
     507           0 :                 p = getInstrPtr(mb, i);
     508           0 :                 for (j = p->retc; j < p->argc; j++)
     509           0 :                         setVarUsed(mb, getArg(p, j));
     510           0 :                 if (p->barrier)
     511           0 :                         for (j = 0; j < p->retc; j++)
     512           0 :                                 setVarUsed(mb, getArg(p, j));
     513             :         }
     514           0 :         for (i = 0; i < mb->stop; i++)
     515           0 :                 traceInstruction(comp, mb, stk, getInstrPtr(mb, i), flg);
     516           0 : }
     517             : 
     518             : /* initialize the static scope boundaries for all variables */
     519             : void
     520     2644477 : setVariableScope(MalBlkPtr mb)
     521             : {
     522     2644477 :         int pc, k, depth = 0, dflow = -1;
     523     2644477 :         InstrPtr p;
     524             : 
     525             :         /* reset the scope admin */
     526   291499547 :         for (k = 0; k < mb->vtop; k++)
     527   288855070 :                 if (isVarConstant(mb, k)) {
     528    78752939 :                         setVarScope(mb, k, 0);
     529    78752939 :                         setVarDeclared(mb, k, 0);
     530    78752939 :                         setVarUpdated(mb, k, 0);
     531    78752939 :                         setVarEolife(mb, k, mb->stop);
     532             :                 } else {
     533   210102131 :                         setVarScope(mb, k, 0);
     534   210102131 :                         setVarDeclared(mb, k, 0);
     535   210102131 :                         setVarUpdated(mb, k, 0);
     536   210102131 :                         setVarEolife(mb, k, 0);
     537             :                 }
     538             : 
     539   150207681 :         for (pc = 0; pc < mb->stop; pc++) {
     540   147563204 :                 p = getInstrPtr(mb, pc);
     541             : 
     542   147563204 :                 if (blockStart(p)) {
     543      475509 :                         if (getModuleId(p) && getFunctionId(p)
     544      471413 :                                 && strcmp(getModuleId(p), "language") == 0
     545      459551 :                                 && strcmp(getFunctionId(p), "dataflow") == 0) {
     546      459584 :                                 if (dflow != -1)
     547           0 :                                         addMalException(mb,
     548             :                                                                         "setLifeSpan nested dataflow blocks not allowed");
     549             :                                 dflow = depth;
     550             :                         } else
     551       15925 :                                 depth++;
     552             :                 }
     553             : 
     554   656358084 :                 for (k = 0; k < p->argc; k++) {
     555   508794880 :                         int v = getArg(p, k);
     556   508794880 :                         if (isVarConstant(mb, v) && getVarUpdated(mb, v) == 0)
     557    71728379 :                                 setVarUpdated(mb, v, pc);
     558             : 
     559   508794880 :                         if (getVarDeclared(mb, v) == 0) {
     560   222114079 :                                 setVarDeclared(mb, v, pc);
     561   222114079 :                                 setVarScope(mb, v, depth);
     562             :                         }
     563   508794880 :                         if (k < p->retc)
     564   151025999 :                                 setVarUpdated(mb, v, pc);
     565   508794880 :                         if (getVarScope(mb, v) == depth)
     566   508706770 :                                 setVarEolife(mb, v, pc);
     567             : 
     568   508794880 :                         if (k >= p->retc && getVarScope(mb, v) < depth)
     569       63765 :                                 setVarEolife(mb, v, -1);
     570             :                 }
     571             :                 /*
     572             :                  * At a block exit we can finalize all variables defined within that block.
     573             :                  * This does not hold for dataflow blocks. They merely direct the execution
     574             :                  * thread, not the syntactic scope.
     575             :                  */
     576   147563204 :                 if (blockExit(p)) {
     577   151310819 :                         for (k = 0; k < mb->vtop; k++)
     578   150835390 :                                 if (getVarEolife(mb, k) == 0 && getVarScope(mb, k) == depth)
     579    48118456 :                                         setVarEolife(mb, k, pc);
     580   102716934 :                                 else if (getVarEolife(mb, k) == -1)
     581       40281 :                                         setVarEolife(mb, k, pc);
     582             : 
     583      475429 :                         if (dflow == depth)
     584             :                                 dflow = -1;
     585             :                         else
     586       15885 :                                 depth--;
     587             :                 }
     588   147563204 :                 if (blockReturn(p)) {
     589       26320 :                         for (k = 0; k < p->argc; k++)
     590       23718 :                                 setVarEolife(mb, getArg(p, k), pc);
     591             :                 }
     592             :         }
     593   291644344 :         for (k = 0; k < mb->vtop; k++)
     594   288999867 :                 if (getVarEolife(mb, k) == 0)
     595    25667011 :                         setVarEolife(mb, k, mb->stop - 1);
     596     2644477 : }
     597             : 
     598             : int
     599           0 : isLoopBarrier(MalBlkPtr mb, int pc)
     600             : {
     601           0 :         InstrPtr p;
     602           0 :         int varid;
     603           0 :         p = getInstrPtr(mb, pc);
     604           0 :         if (p->barrier != BARRIERsymbol)
     605             :                 return 0;
     606           0 :         varid = getDestVar(p);
     607           0 :         for (pc++; pc < mb->stop; pc++) {
     608           0 :                 p = getInstrPtr(mb, pc);
     609           0 :                 if (p->barrier == REDOsymbol && getDestVar(p) == varid)
     610             :                         return 1;
     611           0 :                 if (p->barrier == EXITsymbol && getDestVar(p) == varid)
     612             :                         break;
     613             :         }
     614             :         return 0;
     615             : }
     616             : 
     617             : int
     618           0 : getBlockBegin(MalBlkPtr mb, int pc)
     619             : {
     620           0 :         InstrPtr p;
     621           0 :         int varid = 0, i;
     622             : 
     623           0 :         for (i = pc; i < mb->stop; i++) {
     624           0 :                 p = getInstrPtr(mb, i);
     625           0 :                 if (p->barrier == EXITsymbol) {
     626           0 :                         varid = getDestVar(p);
     627           0 :                         break;
     628             :                 }
     629             :         }
     630           0 :         if (i == mb->stop)
     631             :                 return 0;
     632             : 
     633           0 :         for (; pc > 0; pc--) {
     634           0 :                 p = getInstrPtr(mb, pc);
     635           0 :                 if ((p->barrier == BARRIERsymbol || p->barrier == CATCHsymbol) &&
     636           0 :                         getDestVar(p) == varid)
     637           0 :                         return pc;
     638             :         }
     639             :         return 0;
     640             : }
     641             : 
     642             : int
     643           0 : getBlockExit(MalBlkPtr mb, int pc)
     644             : {
     645           0 :         InstrPtr p;
     646           0 :         int varid;
     647           0 :         p = getInstrPtr(mb, pc);
     648           0 :         if (p->barrier != BARRIERsymbol && p->barrier != CATCHsymbol)
     649             :                 return 0;
     650           0 :         varid = getDestVar(p);
     651           0 :         for (pc++; pc < mb->stop; pc++) {
     652           0 :                 p = getInstrPtr(mb, pc);
     653           0 :                 if (p->barrier == EXITsymbol && getDestVar(p) == varid)
     654           0 :                         return pc;
     655             :         }
     656             :         return 0;
     657             : }
     658             : 
     659             : /*
     660             :  * Variable declaration
     661             :  * Variables are implicitly declared upon first use.
     662             :  * This feature may become a source of runtime errors and
     663             :  * complicates the analyse during optimization.
     664             :  * Therefore, in line with the flow of control check,
     665             :  * we make sure that all variables are properly initialized
     666             :  * before being used. Since barrier blocks may be skipped at
     667             :  * runtime, they actually introduce a separate scope.
     668             :  * Variables declared within a block may not be used outside it.
     669             :  * Variables can only be declared once.
     670             :  *
     671             :  * In many situation chkFlow and chkDeclarations should be called
     672             :  * together. Moreover, an erroneous chkFlow most likely implies
     673             :  * errors in the declarations as well.
     674             :  *
     675             :  * Since in interactive mode each statement is handled separately,
     676             :  * we have to remember the scope assigned to a variable.
     677             :  */
     678             : void
     679           0 : clrDeclarations(MalBlkPtr mb)
     680             : {
     681           0 :         int i;
     682           0 :         for (i = 0; i < mb->vtop; i++) {
     683           0 :                 clrVarInit(mb, i);
     684           0 :                 clrVarUsed(mb, i);
     685           0 :                 clrVarDisabled(mb, i);
     686             :         }
     687           0 : }
     688             : 
     689             : str
     690     3242072 : chkDeclarations(MalBlkPtr mb)
     691             : {
     692     3242072 :         int pc, i, k, l;
     693     3242072 :         InstrPtr p, sig;
     694     3242072 :         short blks[MAXDEPTH], top = 0, blkId = 1;
     695     3242072 :         int dflow = -1;
     696     3242072 :         str msg = MAL_SUCCEED;
     697     3242072 :         char name[IDLENGTH] = { 0 };
     698             : 
     699     3242072 :         if (mb->errors)
     700           0 :                 return GDKstrdup(mb->errors);
     701     3242072 :         blks[top] = blkId;
     702             : 
     703             :         /* initialize the scope */
     704   402265571 :         for (i = 0; i < mb->vtop; i++)
     705   399023499 :                 setVarScope(mb, i, 0);
     706             : 
     707             :         /* all signature variables are declared at outer level */
     708     3242072 :         sig = getInstrPtr(mb, 0);
     709     6503177 :         for (k = 0; k < sig->argc; k++)
     710     3261105 :                 setVarScope(mb, getArg(sig, k), blkId);
     711             : 
     712   206197321 :         for (pc = 1; pc < mb->stop; pc++) {
     713   202955254 :                 p = getInstrPtr(mb, pc);
     714   202955254 :                 if (p->token == REMsymbol)
     715    26195304 :                         continue;
     716             :                 /* check correct use of the arguments */
     717   698700360 :                 for (k = p->retc; k < p->argc; k++) {
     718   521940415 :                         l = getArg(p, k);
     719   521940415 :                         if (l < 0)
     720           0 :                                 throw(MAL, "chkFlow",
     721             :                                           "%s.%s Non-declared variable: pc=%d, var= %d",
     722             :                                           getModuleId(sig), getFunctionId(sig), pc, k);
     723   521940415 :                         setVarUsed(mb, l);
     724   521940415 :                         if (getVarScope(mb, l) == 0) {
     725             :                                 /*
     726             :                                  * The problem created here is that only variables are
     727             :                                  * recognized that are declared through instructions.
     728             :                                  * For interactive code, and code that is based on a global
     729             :                                  * stack this is insufficient. In those cases, the variable
     730             :                                  * can be defined in a previous execution.
     731             :                                  * We have to recognize if the declaration takes place
     732             :                                  * in the context of a global stack.
     733             :                                  */
     734   210625624 :                                 if (p->barrier == CATCHsymbol) {
     735           0 :                                         setVarScope(mb, l, blks[0]);
     736   210625624 :                                 } else if (!(isVarConstant(mb, l) || isVarTypedef(mb, l))
     737       11341 :                                                    && !isVarInit(mb, l)) {
     738           5 :                                         throw(MAL, "chkFlow",
     739             :                                                   "%s.%s '%s' may not be used before being initialized",
     740             :                                                   getModuleId(sig), getFunctionId(sig), getVarNameIntoBuffer(mb, l, name));
     741             :                                 }
     742   311314791 :                         } else if (!isVarInit(mb, l)) {
     743             :                                 /* is the block still active ? */
     744       10204 :                                 for (i = 0; i <= top; i++)
     745       10204 :                                         if (blks[i] == getVarScope(mb, l))
     746             :                                                 break;
     747       10204 :                                 if (i > top || blks[i] != getVarScope(mb, l))
     748           0 :                                         throw(MAL, "chkFlow", "%s.%s '%s' used outside scope",
     749             :                                                   getModuleId(sig), getFunctionId(sig), getVarNameIntoBuffer(mb, l, name));
     750             :                         }
     751   521940410 :                         if (blockCntrl(p) || blockStart(p))
     752      336855 :                                 setVarInit(mb, l);
     753             :                 }
     754             :                 /* define variables */
     755   363041812 :                 for (k = 0; k < p->retc; k++) {
     756   186281867 :                         l = getArg(p, k);
     757   186281867 :                         if (isVarInit(mb, l) && getVarScope(mb, l) == 0) {
     758             :                                 /* first time we see this variable and it is already
     759             :                                  * initialized: assume it exists globally */
     760   143101065 :                                 setVarScope(mb, l, blks[0]);
     761             :                         }
     762   186281867 :                         setVarInit(mb, l);
     763   186281867 :                         if (getVarScope(mb, l) == 0) {
     764             :                                 /* variable has not been defined yet */
     765             :                                 /* exceptions are always declared at level 1 */
     766    42887511 :                                 if (p->barrier == CATCHsymbol)
     767         200 :                                         setVarScope(mb, l, blks[0]);
     768             :                                 else
     769    42887311 :                                         setVarScope(mb, l, blks[top]);
     770             :                         }
     771   186281867 :                         if (blockCntrl(p) || blockStart(p))
     772      309500 :                                 setVarUsed(mb, l);
     773             :                 }
     774   176759945 :                 if (p->barrier && msg == MAL_SUCCEED) {
     775      547618 :                         if (blockStart(p)) {
     776      267543 :                                 if (top == MAXDEPTH - 2)
     777           0 :                                         throw(MAL, "chkFlow",
     778             :                                                   "%s.%s too deeply nested  MAL program",
     779             :                                                   getModuleId(sig), getFunctionId(sig));
     780      267543 :                                 blkId++;
     781      267543 :                                 if (getModuleId(p) && getFunctionId(p)
     782      262148 :                                         && strcmp(getModuleId(p), "language") == 0
     783      254284 :                                         && strcmp(getFunctionId(p), "dataflow") == 0) {
     784      254300 :                                         if (dflow != -1)
     785           0 :                                                 throw(MAL, "chkFlow",
     786             :                                                           "%s.%s setLifeSpan nested dataflow blocks not allowed",
     787             :                                                           getModuleId(sig), getFunctionId(sig));
     788      254300 :                                         dflow = blkId;
     789             :                                 }
     790      267543 :                                 blks[++top] = blkId;
     791             :                         }
     792      547618 :                         if (blockExit(p) && top > 0) {
     793      267685 :                                 if (dflow == blkId) {
     794             :                                         dflow = -1;
     795             :                                 } else
     796             :                                         /*
     797             :                                          * At the end of the block we should reset the status of all variables
     798             :                                          * defined within the block. For, the block could have been skipped
     799             :                                          * leading to uninitialized variables.
     800             :                                          */
     801    10309783 :                                         for (l = 0; l < mb->vtop; l++)
     802    10296457 :                                                 if (getVarScope(mb, l) == blks[top]) {
     803       59869 :                                                         setVarScope(mb, l, 0);
     804       59869 :                                                         clrVarInit(mb, l);
     805             :                                                 }
     806      267685 :                                 top--;
     807             :                         }
     808             :                 }
     809             :         }
     810             :         return msg;
     811             : }

Generated by: LCOV version 1.14