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-11-14 20:04:02 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       49331 : newFunctionArgs(const char *mod, const char *nme, int kind, int args)
      27             : {
      28       49331 :         Symbol s;
      29             : 
      30       49331 :         if (mod == NULL || nme == NULL)
      31             :                 return NULL;
      32             : 
      33       49331 :         s = newSymbol(nme, kind);
      34       49331 :         if (s == NULL)
      35             :                 return NULL;
      36             : 
      37       49331 :         if (kind == FUNCTIONsymbol) {
      38       49318 :                 int varid = newVariable(s->def, nme, strlen(nme), TYPE_any);
      39       49318 :                 if (varid < 0) {
      40           0 :                         freeSymbol(s);
      41           0 :                         return NULL;
      42             :                 }
      43             : 
      44       49318 :                 if (args > 0) {
      45       49307 :                         InstrPtr p = newInstructionArgs(NULL, mod, nme, args);
      46       49307 :                         if (p == NULL) {
      47           0 :                                 freeSymbol(s);
      48           0 :                                 return NULL;
      49             :                         }
      50       49307 :                         p->token = kind;
      51       49307 :                         p->barrier = 0;
      52       49307 :                         setDestVar(p, varid);
      53       49307 :                         pushInstruction(s->def, p);
      54       49307 :                         if (s->def->errors) {
      55           0 :                                 freeSymbol(s);
      56           0 :                                 return NULL;
      57             :                         }
      58             :                 }
      59             :         }
      60             :         return s;
      61             : }
      62             : 
      63             : Symbol
      64       48102 : newFunction(const char *mod, const char *nme, int kind)
      65             : {
      66       48102 :         return newFunctionArgs(mod, nme, kind, MAXARG);
      67             : }
      68             : 
      69             : int
      70      154959 : getPC(MalBlkPtr mb, InstrPtr p)
      71             : {
      72      154959 :         int i;
      73     1795856 :         for (i = 0; i < mb->stop; i++)
      74     1795856 :                 if (getInstrPtr(mb, i) == p)
      75      154959 :                         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     3199455 : chkFlow(MalBlkPtr mb)
      90             : {
      91     3199455 :         int i, j, k, v, lastInstruction;
      92     3199455 :         int pc[DEPTH];
      93     3199455 :         int var[DEPTH];
      94     3199455 :         InstrPtr stmt[DEPTH];
      95     3199455 :         int btop = 0;
      96     3199455 :         int endseen = 0, retseen = 0;
      97     3199455 :         InstrPtr p, sig;
      98     3199455 :         str msg = MAL_SUCCEED;
      99     3199455 :         char name[IDLENGTH] = { 0 };
     100             : 
     101     3199455 :         if (mb->errors != MAL_SUCCEED)
     102             :                 return mb->errors;
     103     3199342 :         sig = getInstrPtr(mb, 0);
     104     3199342 :         lastInstruction = mb->stop - 1;
     105   181400677 :         for (i = 0; i < mb->stop; i++) {
     106   178201348 :                 p = getInstrPtr(mb, i);
     107             :                 /* we have to keep track on the maximal arguments/block
     108             :                    because it is needed by the interpreter */
     109   178201348 :                 switch (p->barrier) {
     110      255416 :                 case BARRIERsymbol:
     111             :                 case CATCHsymbol:
     112      255416 :                         if (btop == DEPTH)
     113           0 :                                 throw(MAL, "chkFlow", "%s.%s Too many nested MAL blocks",
     114             :                                           getModuleId(sig), getFunctionId(sig));
     115      255416 :                         pc[btop] = i;
     116      255416 :                         v = var[btop] = getDestVar(p);
     117      255416 :                         stmt[btop] = p;
     118             : 
     119      256169 :                         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      255416 :                         btop++;
     127      255416 :                         break;
     128      255412 :                 case EXITsymbol:
     129      255412 :                         v = getDestVar(p);
     130      255412 :                         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      255409 :                         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      255409 :                         for (j = btop - 1; j >= 0; j--)
     141      255409 :                                 if (var[j] == v)
     142             :                                         break;
     143      255409 :                         if (j >= 0)
     144             :                                 btop = j;
     145             :                         else
     146           0 :                                 btop--;
     147             : 
     148             :                         /* retrofit LEAVE/REDO instructions */
     149      255409 :                         stmt[btop]->jump = i;
     150    17399775 :                         for (k = pc[btop]; k < i; k++) {
     151    17144366 :                                 InstrPtr p1 = getInstrPtr(mb, k);
     152    17144366 :                                 if (getDestVar(p1) == v) {
     153             :                                         /* handle assignments with leave/redo option */
     154      260384 :                                         if (p1->barrier == LEAVEsymbol)
     155         126 :                                                 p1->jump = i;
     156      260384 :                                         if (p1->barrier == REDOsymbol)
     157        4852 :                                                 p1->jump = pc[btop] + 1;
     158             :                                 }
     159             :                         }
     160             :                         break;
     161        4992 :                 case LEAVEsymbol:
     162             :                 case REDOsymbol:
     163        4992 :                         v = getDestVar(p);
     164        5001 :                         for (j = btop - 1; j >= 0; j--)
     165        4993 :                                 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        3602 :                 case RETURNsymbol: {
     174        3602 :                         InstrPtr ps = getInstrPtr(mb, 0);
     175        3602 :                         int e;
     176        3602 :                         if (ps->retc != p->retc) {
     177           2 :                                 throw(MAL, "chkFlow", "%s.%s invalid return target!",
     178             :                                           getModuleId(sig), getFunctionId(sig));
     179        3600 :                         } else if (ps->typeresolved)
     180       21774 :                                 for (e = 0; e < p->retc; e++) {
     181       18182 :                                         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   177681291 :                 default:
     204   177681291 :                         if (isaSignature(p)) {
     205    28970528 :                                 if (p->token == REMsymbol) {
     206             :                                         /* do nothing */
     207     3199186 :                                 } 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     3199329 :         if (lastInstruction < mb->stop - 1)
     219           0 :                 throw(MAL, "chkFlow", "%s.%s instructions after END", getModuleId(sig),
     220             :                           getFunctionId(sig));
     221             : 
     222     3199329 :         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     3199329 :         p = getInstrPtr(mb, 0);
     226     3199329 :         if (!isaSignature(p))
     227           0 :                 throw(MAL, "chkFlow", "%s.%s signature missing", getModuleId(sig),
     228             :                           getFunctionId(sig));
     229     3199329 :         if (retseen == 0) {
     230     3196727 :                 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          68 : listFunction(stream *fd, MalBlkPtr mb, MalStkPtr stk, int flg, int first,
     436             :                          int size)
     437             : {
     438          68 :         int i;
     439          68 :         int sample = 256;
     440             : 
     441          68 :         if (mb == NULL) {
     442           0 :                 mnstr_printf(fd, "# function definition missing\n");
     443           0 :                 return;
     444             :         }
     445          68 :         if (flg == 0)
     446             :                 return;
     447             : 
     448          68 :         assert(size >= 0);
     449          68 :         assert(first >= 0 && first < mb->stop);
     450          68 :         if (flg & LIST_MAL_MAPI) {
     451          64 :                 size_t len = 0;
     452          64 :                 str ps;
     453          64 :                 mnstr_printf(fd, "&1 0 %d 1 %d\n",        /* type id rows columns tuples */
     454             :                                          mb->stop, mb->stop);
     455          64 :                 mnstr_printf(fd, "%% .explain # table_name\n");
     456          64 :                 mnstr_printf(fd, "%% mal # name\n");
     457          64 :                 mnstr_printf(fd, "%% clob # type\n");
     458        3099 :                 for (i = first; i < first + size && i < mb->stop && sample-- > 0; i++) {
     459        2971 :                         ps = instruction2str(mb, stk, getInstrPtr(mb, i), flg);
     460        2971 :                         if (ps) {
     461        2971 :                                 size_t l = strlen(ps);
     462        2971 :                                 if (l > len)
     463             :                                         len = l;
     464        2971 :                                 GDKfree(ps);
     465             :                         } else
     466           0 :                                 mnstr_printf(fd, "#failed instruction2str()\n");
     467             :                 }
     468          64 :                 mnstr_printf(fd, "%% %zu # length\n", len);
     469             :         }
     470        3079 :         for (i = first; i < first + size && i < mb->stop; i++)
     471        3011 :                 printInstruction(fd, mb, stk, getInstrPtr(mb, i), flg);
     472             : }
     473             : 
     474             : 
     475             : void
     476          68 : printFunction(stream *fd, MalBlkPtr mb, MalStkPtr stk, int flg)
     477             : {
     478          68 :         int i, j;
     479          68 :         InstrPtr p;
     480             : 
     481             : 
     482             :         // Set the used bits properly
     483        6747 :         for (i = 0; i < mb->vtop; i++)
     484        6679 :                 clrVarUsed(mb, i);
     485             : 
     486             : 
     487        3079 :         for (i = 0; i < mb->stop; i++) {
     488        3011 :                 p = getInstrPtr(mb, i);
     489        9775 :                 for (j = p->retc; j < p->argc; j++)
     490        6764 :                         setVarUsed(mb, getArg(p, j));
     491        3011 :                 if (p->barrier)
     492          24 :                         for (j = 0; j < p->retc; j++)
     493          12 :                                 setVarUsed(mb, getArg(p, j));
     494             :         }
     495          68 :         listFunction(fd, mb, stk, flg, 0, mb->stop);
     496          68 : }
     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     2599358 : setVariableScope(MalBlkPtr mb)
     521             : {
     522     2599358 :         int pc, k, depth = 0, dflow = -1;
     523     2599358 :         InstrPtr p;
     524             : 
     525             :         /* reset the scope admin */
     526   262008125 :         for (k = 0; k < mb->vtop; k++)
     527   259408767 :                 if (isVarConstant(mb, k)) {
     528    78304590 :                         setVarScope(mb, k, 0);
     529    78304590 :                         setVarDeclared(mb, k, 0);
     530    78304590 :                         setVarUpdated(mb, k, 0);
     531    78304590 :                         setVarEolife(mb, k, mb->stop);
     532             :                 } else {
     533   181104177 :                         setVarScope(mb, k, 0);
     534   181104177 :                         setVarDeclared(mb, k, 0);
     535   181104177 :                         setVarUpdated(mb, k, 0);
     536   181104177 :                         setVarEolife(mb, k, 0);
     537             :                 }
     538             : 
     539   132778862 :         for (pc = 0; pc < mb->stop; pc++) {
     540   130179504 :                 p = getInstrPtr(mb, pc);
     541             : 
     542   130179504 :                 if (blockStart(p)) {
     543      440852 :                         if (getModuleId(p) && getFunctionId(p)
     544      436737 :                                 && strcmp(getModuleId(p), "language") == 0
     545      429740 :                                 && strcmp(getFunctionId(p), "dataflow") == 0) {
     546      429736 :                                 if (dflow != -1)
     547           0 :                                         addMalException(mb,
     548             :                                                                         "setLifeSpan nested dataflow blocks not allowed");
     549             :                                 dflow = depth;
     550             :                         } else
     551       11116 :                                 depth++;
     552             :                 }
     553             : 
     554   551571592 :                 for (k = 0; k < p->argc; k++) {
     555   421392088 :                         int v = getArg(p, k);
     556   421392088 :                         if (isVarConstant(mb, v) && getVarUpdated(mb, v) == 0)
     557    71141450 :                                 setVarUpdated(mb, v, pc);
     558             : 
     559   421392088 :                         if (getVarDeclared(mb, v) == 0) {
     560   202476964 :                                 setVarDeclared(mb, v, pc);
     561   202476964 :                                 setVarScope(mb, v, depth);
     562             :                         }
     563   421392088 :                         if (k < p->retc)
     564   131888925 :                                 setVarUpdated(mb, v, pc);
     565   421392088 :                         if (getVarScope(mb, v) == depth)
     566   421309968 :                                 setVarEolife(mb, v, pc);
     567             : 
     568   421392088 :                         if (k >= p->retc && getVarScope(mb, v) < depth)
     569       45096 :                                 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   130179504 :                 if (blockExit(p)) {
     577   118657223 :                         for (k = 0; k < mb->vtop; k++)
     578   118216372 :                                 if (getVarEolife(mb, k) == 0 && getVarScope(mb, k) == depth)
     579    39300662 :                                         setVarEolife(mb, k, pc);
     580    78915710 :                                 else if (getVarEolife(mb, k) == -1)
     581       26411 :                                         setVarEolife(mb, k, pc);
     582             : 
     583      440851 :                         if (dflow == depth)
     584             :                                 dflow = -1;
     585             :                         else
     586       11115 :                                 depth--;
     587             :                 }
     588   130179504 :                 if (blockReturn(p)) {
     589       26392 :                         for (k = 0; k < p->argc; k++)
     590       23766 :                                 setVarEolife(mb, getArg(p, k), pc);
     591             :                 }
     592             :         }
     593   262125956 :         for (k = 0; k < mb->vtop; k++)
     594   259526598 :                 if (getVarEolife(mb, k) == 0)
     595    23437824 :                         setVarEolife(mb, k, mb->stop - 1);
     596     2599358 : }
     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     3199225 : chkDeclarations(MalBlkPtr mb)
     691             : {
     692     3199225 :         int pc, i, k, l;
     693     3199225 :         InstrPtr p, sig;
     694     3199225 :         short blks[MAXDEPTH], top = 0, blkId = 1;
     695     3199225 :         int dflow = -1;
     696     3199225 :         str msg = MAL_SUCCEED;
     697     3199225 :         char name[IDLENGTH] = { 0 };
     698             : 
     699     3199225 :         if (mb->errors)
     700           0 :                 return GDKstrdup(mb->errors);
     701     3199225 :         blks[top] = blkId;
     702             : 
     703             :         /* initialize the scope */
     704   351713449 :         for (i = 0; i < mb->vtop; i++)
     705   348514224 :                 setVarScope(mb, i, 0);
     706             : 
     707             :         /* all signature variables are declared at outer level */
     708     3199225 :         sig = getInstrPtr(mb, 0);
     709     6419591 :         for (k = 0; k < sig->argc; k++)
     710     3220366 :                 setVarScope(mb, getArg(sig, k), blkId);
     711             : 
     712   178095021 :         for (pc = 1; pc < mb->stop; pc++) {
     713   174895801 :                 p = getInstrPtr(mb, pc);
     714   174895801 :                 if (p->token == REMsymbol)
     715    25771734 :                         continue;
     716             :                 /* check correct use of the arguments */
     717   524682483 :                 for (k = p->retc; k < p->argc; k++) {
     718   375558421 :                         l = getArg(p, k);
     719   375558421 :                         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   375558421 :                         setVarUsed(mb, l);
     724   375558421 :                         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   161999677 :                                 if (p->barrier == CATCHsymbol) {
     735           0 :                                         setVarScope(mb, l, blks[0]);
     736   161999677 :                                 } else if (!(isVarConstant(mb, l) || isVarTypedef(mb, l))
     737       11372 :                                                    && !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   213558744 :                         } else if (!isVarInit(mb, l)) {
     743             :                                 /* is the block still active ? */
     744       10285 :                                 for (i = 0; i <= top; i++)
     745       10285 :                                         if (blks[i] == getVarScope(mb, l))
     746             :                                                 break;
     747       10285 :                                 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   375558416 :                         if (blockCntrl(p) || blockStart(p))
     752      181568 :                                 setVarInit(mb, l);
     753             :                 }
     754             :                 /* define variables */
     755   304468867 :                 for (k = 0; k < p->retc; k++) {
     756   155344805 :                         l = getArg(p, k);
     757   155344805 :                         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   119207242 :                                 setVarScope(mb, l, blks[0]);
     761             :                         }
     762   155344805 :                         setVarInit(mb, l);
     763   155344805 :                         if (getVarScope(mb, l) == 0) {
     764             :                                 /* variable has not been defined yet */
     765             :                                 /* exceptions are always declared at level 1 */
     766    35846624 :                                 if (p->barrier == CATCHsymbol)
     767         200 :                                         setVarScope(mb, l, blks[0]);
     768             :                                 else
     769    35846424 :                                         setVarScope(mb, l, blks[top]);
     770             :                         }
     771   155344805 :                         if (blockCntrl(p) || blockStart(p))
     772      287926 :                                 setVarUsed(mb, l);
     773             :                 }
     774   149124062 :                 if (p->barrier && msg == MAL_SUCCEED) {
     775      519990 :                         if (blockStart(p)) {
     776      255399 :                                 if (top == MAXDEPTH - 2)
     777           0 :                                         throw(MAL, "chkFlow",
     778             :                                                   "%s.%s too deeply nested  MAL program",
     779             :                                                   getModuleId(sig), getFunctionId(sig));
     780      255399 :                                 blkId++;
     781      255399 :                                 if (getModuleId(p) && getFunctionId(p)
     782      249977 :                                         && strcmp(getModuleId(p), "language") == 0
     783      245243 :                                         && strcmp(getFunctionId(p), "dataflow") == 0) {
     784      245243 :                                         if (dflow != -1)
     785           0 :                                                 throw(MAL, "chkFlow",
     786             :                                                           "%s.%s setLifeSpan nested dataflow blocks not allowed",
     787             :                                                           getModuleId(sig), getFunctionId(sig));
     788      245243 :                                         dflow = blkId;
     789             :                                 }
     790      255399 :                                 blks[++top] = blkId;
     791             :                         }
     792      519990 :                         if (blockExit(p) && top > 0) {
     793      255393 :                                 if (dflow == blks[top]) {
     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     5786966 :                                         for (l = 0; l < mb->vtop; l++)
     802     5776810 :                                                 if (getVarScope(mb, l) == blks[top]) {
     803       54016 :                                                         setVarScope(mb, l, 0);
     804       54016 :                                                         clrVarInit(mb, l);
     805             :                                                 }
     806      255393 :                                 top--;
     807             :                         }
     808             :                 }
     809             :         }
     810             :         return msg;
     811             : }

Generated by: LCOV version 1.14