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

Generated by: LCOV version 1.14