LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_interpreter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 410 602 68.1 %
Date: 2021-09-14 22:17:06 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * Author M. Kersten
      11             :  * The MAL Interpreter
      12             :  */
      13             : #include "monetdb_config.h"
      14             : #include "mal_runtime.h"
      15             : #include "mal_interpreter.h"
      16             : #include "mal_resource.h"
      17             : #include "mal_listing.h"
      18             : #include "mal_debugger.h"   /* for mdbStep() */
      19             : #include "mal_type.h"
      20             : #include "mal_private.h"
      21             : #include "mal_internal.h"
      22             : #include "mal_function.h"
      23             : 
      24             : static lng qptimeout = 0; /* how often we print still running queries (usec) */
      25             : 
      26             : void
      27           0 : setqptimeout(lng usecs)
      28             : {
      29           0 :         qptimeout = usecs;
      30           0 : }
      31             : 
      32             : inline
      33     1545536 : ptr getArgReference(MalStkPtr stk, InstrPtr pci, int k)
      34             : {
      35             :         /* the C standard says: "A pointer to a union object, suitably
      36             :          * converted, points to each of its members (or if a member is a
      37             :          * bit-field, then to the unit in which it resides), and vice
      38             :          * versa." */
      39    43429590 :         return (ptr) &stk->stk[pci->argv[k]].val;
      40             : }
      41             : 
      42    41884054 : str malCommandCall(MalStkPtr stk, InstrPtr pci)
      43             : {
      44             :         str ret= MAL_SUCCEED;
      45             : 
      46    41884054 :         switch (pci->argc) {
      47           0 :         case 0: ret = (*pci->fcn)();
      48           0 :                 break;
      49     1010193 :         case 1: ret = (*pci->fcn)(
      50             :                         getArgReference(stk, pci, 0));
      51     1010193 :                 break;
      52      203216 :         case 2: ret = (*pci->fcn)(
      53             :                         getArgReference(stk, pci, 0),
      54             :                         getArgReference(stk, pci, 1));
      55      203257 :                 break;
      56    37466563 :         case 3: ret = (*pci->fcn)(
      57             :                         getArgReference(stk, pci, 0),
      58             :                         getArgReference(stk, pci, 1),
      59             :                         getArgReference(stk, pci, 2));
      60    37454790 :                 break;
      61     1036313 :         case 4: ret = (*pci->fcn)(
      62             :                         getArgReference(stk, pci, 0),
      63             :                         getArgReference(stk, pci, 1),
      64             :                         getArgReference(stk, pci, 2),
      65             :                         getArgReference(stk, pci, 3));
      66     1037015 :                 break;
      67     1182362 :         case 5: ret = (*pci->fcn)(
      68             :                         getArgReference(stk, pci, 0),
      69             :                         getArgReference(stk, pci, 1),
      70             :                         getArgReference(stk, pci, 2),
      71             :                         getArgReference(stk, pci, 3),
      72             :                         getArgReference(stk, pci, 4));
      73     1184210 :                 break;
      74       17417 :         case 6: ret = (*pci->fcn)(
      75             :                         getArgReference(stk, pci, 0),
      76             :                         getArgReference(stk, pci, 1),
      77             :                         getArgReference(stk, pci, 2),
      78             :                         getArgReference(stk, pci, 3),
      79             :                         getArgReference(stk, pci, 4),
      80             :                         getArgReference(stk, pci, 5));
      81       17421 :                 break;
      82      135904 :         case 7: ret = (*pci->fcn)(
      83             :                         getArgReference(stk, pci, 0),
      84             :                         getArgReference(stk, pci, 1),
      85             :                         getArgReference(stk, pci, 2),
      86             :                         getArgReference(stk, pci, 3),
      87             :                         getArgReference(stk, pci, 4),
      88             :                         getArgReference(stk, pci, 5),
      89             :                         getArgReference(stk, pci, 6));
      90      135998 :                 break;
      91      807488 :         case 8: ret = (*pci->fcn)(
      92             :                         getArgReference(stk, pci, 0),
      93             :                         getArgReference(stk, pci, 1),
      94             :                         getArgReference(stk, pci, 2),
      95             :                         getArgReference(stk, pci, 3),
      96             :                         getArgReference(stk, pci, 4),
      97             :                         getArgReference(stk, pci, 5),
      98             :                         getArgReference(stk, pci, 6),
      99             :                         getArgReference(stk, pci, 7));
     100      809438 :                 break;
     101       24436 :         case 9: ret = (*pci->fcn)(
     102             :                         getArgReference(stk, pci, 0),
     103             :                         getArgReference(stk, pci, 1),
     104             :                         getArgReference(stk, pci, 2),
     105             :                         getArgReference(stk, pci, 3),
     106             :                         getArgReference(stk, pci, 4),
     107             :                         getArgReference(stk, pci, 5),
     108             :                         getArgReference(stk, pci, 6),
     109             :                         getArgReference(stk, pci, 7),
     110             :                         getArgReference(stk, pci, 8));
     111       25074 :                 break;
     112          16 :         case 10: ret = (*pci->fcn)(
     113             :                         getArgReference(stk, pci, 0),
     114             :                         getArgReference(stk, pci, 1),
     115             :                         getArgReference(stk, pci, 2),
     116             :                         getArgReference(stk, pci, 3),
     117             :                         getArgReference(stk, pci, 4),
     118             :                         getArgReference(stk, pci, 5),
     119             :                         getArgReference(stk, pci, 6),
     120             :                         getArgReference(stk, pci, 7),
     121             :                         getArgReference(stk, pci, 8),
     122             :                         getArgReference(stk, pci, 9));
     123          16 :                 break;
     124          32 :         case 11: ret = (*pci->fcn)(
     125             :                         getArgReference(stk, pci, 0),
     126             :                         getArgReference(stk, pci, 1),
     127             :                         getArgReference(stk, pci, 2),
     128             :                         getArgReference(stk, pci, 3),
     129             :                         getArgReference(stk, pci, 4),
     130             :                         getArgReference(stk, pci, 5),
     131             :                         getArgReference(stk, pci, 6),
     132             :                         getArgReference(stk, pci, 7),
     133             :                         getArgReference(stk, pci, 8),
     134             :                         getArgReference(stk, pci, 9),
     135             :                         getArgReference(stk, pci, 10));
     136          32 :                 break;
     137         114 :         case 12: ret = (*pci->fcn)(
     138             :                         getArgReference(stk, pci, 0),
     139             :                         getArgReference(stk, pci, 1),
     140             :                         getArgReference(stk, pci, 2),
     141             :                         getArgReference(stk, pci, 3),
     142             :                         getArgReference(stk, pci, 4),
     143             :                         getArgReference(stk, pci, 5),
     144             :                         getArgReference(stk, pci, 6),
     145             :                         getArgReference(stk, pci, 7),
     146             :                         getArgReference(stk, pci, 8),
     147             :                         getArgReference(stk, pci, 9),
     148             :                         getArgReference(stk, pci, 10),
     149             :                         getArgReference(stk, pci, 11));
     150         115 :                 break;
     151           0 :         case 13: ret = (*pci->fcn)(
     152             :                         getArgReference(stk, pci, 0),
     153             :                         getArgReference(stk, pci, 1),
     154             :                         getArgReference(stk, pci, 2),
     155             :                         getArgReference(stk, pci, 3),
     156             :                         getArgReference(stk, pci, 4),
     157             :                         getArgReference(stk, pci, 5),
     158             :                         getArgReference(stk, pci, 6),
     159             :                         getArgReference(stk, pci, 7),
     160             :                         getArgReference(stk, pci, 8),
     161             :                         getArgReference(stk, pci, 9),
     162             :                         getArgReference(stk, pci, 10),
     163             :                         getArgReference(stk, pci, 11),
     164             :                         getArgReference(stk, pci, 12));
     165           0 :                 break;
     166           0 :         case 14: ret = (*pci->fcn)(
     167             :                         getArgReference(stk, pci, 0),
     168             :                         getArgReference(stk, pci, 1),
     169             :                         getArgReference(stk, pci, 2),
     170             :                         getArgReference(stk, pci, 3),
     171             :                         getArgReference(stk, pci, 4),
     172             :                         getArgReference(stk, pci, 5),
     173             :                         getArgReference(stk, pci, 6),
     174             :                         getArgReference(stk, pci, 7),
     175             :                         getArgReference(stk, pci, 8),
     176             :                         getArgReference(stk, pci, 9),
     177             :                         getArgReference(stk, pci, 10),
     178             :                         getArgReference(stk, pci, 11),
     179             :                         getArgReference(stk, pci, 12),
     180             :                         getArgReference(stk, pci, 13));
     181           0 :                 break;
     182           0 :         case 15: ret = (*pci->fcn)(
     183             :                         getArgReference(stk, pci, 0),
     184             :                         getArgReference(stk, pci, 1),
     185             :                         getArgReference(stk, pci, 2),
     186             :                         getArgReference(stk, pci, 3),
     187             :                         getArgReference(stk, pci, 4),
     188             :                         getArgReference(stk, pci, 5),
     189             :                         getArgReference(stk, pci, 6),
     190             :                         getArgReference(stk, pci, 7),
     191             :                         getArgReference(stk, pci, 8),
     192             :                         getArgReference(stk, pci, 9),
     193             :                         getArgReference(stk, pci, 10),
     194             :                         getArgReference(stk, pci, 11),
     195             :                         getArgReference(stk, pci, 12),
     196             :                         getArgReference(stk, pci, 13),
     197             :                         getArgReference(stk, pci, 14));
     198           0 :                 break;
     199           0 :         case 16: ret = (*pci->fcn)(
     200             :                         getArgReference(stk, pci, 0),
     201             :                         getArgReference(stk, pci, 1),
     202             :                         getArgReference(stk, pci, 2),
     203             :                         getArgReference(stk, pci, 3),
     204             :                         getArgReference(stk, pci, 4),
     205             :                         getArgReference(stk, pci, 5),
     206             :                         getArgReference(stk, pci, 6),
     207             :                         getArgReference(stk, pci, 7),
     208             :                         getArgReference(stk, pci, 8),
     209             :                         getArgReference(stk, pci, 9),
     210             :                         getArgReference(stk, pci, 10),
     211             :                         getArgReference(stk, pci, 11),
     212             :                         getArgReference(stk, pci, 12),
     213             :                         getArgReference(stk, pci, 13),
     214             :                         getArgReference(stk, pci, 14),
     215             :                         getArgReference(stk, pci, 15));
     216           0 :                 break;
     217           0 :         default:
     218           0 :                 throw(MAL, "mal.interpreter", "too many arguments for command call");
     219             :         }
     220             :         return ret;
     221             : }
     222             : 
     223             : /*
     224             :  * Copy the constant values onto the stack frame
     225             :  * Also we cannot overwrite values on the stack as this maybe part of a
     226             :  * sequence of factory calls.
     227             :  */
     228             : #define initStack(S, R)\
     229             :         for (i = S; i < mb->vtop; i++) {\
     230             :                 lhs = &stk->stk[i];\
     231             :                 if (isVarConstant(mb, i) > 0) {\
     232             :                         if (!isVarDisabled(mb, i)) {\
     233             :                                 rhs = &getVarConstant(mb, i);\
     234             :                                 if(VALcopy(lhs, rhs) == NULL) \
     235             :                                         R = 0; \
     236             :                         }\
     237             :                 } else {\
     238             :                         lhs->vtype = getVarGDKType(mb, i);\
     239             :                         lhs->val.pval = 0;\
     240             :                         lhs->len = 0;\
     241             :                 }\
     242             :         }
     243             : 
     244             : int
     245    14699346 : isNotUsedIn(InstrPtr p, int start, int a)
     246             : {
     247             :         int k;
     248    31296979 :         for (k = start; k < p->argc; k++)
     249    16639288 :                 if (getArg(p, k) == a)
     250             :                         return 0;
     251             :         return 1;
     252             : }
     253             : 
     254             : MalStkPtr
     255      404694 : prepareMALstack(MalBlkPtr mb, int size)
     256             : {
     257             :         MalStkPtr stk = NULL;
     258             :         int i, res = 1;
     259             :         ValPtr lhs, rhs;
     260             : 
     261      404694 :         stk = newGlobalStack(size);
     262      404699 :         if (!stk)
     263             :                 return NULL;
     264      404699 :         stk->stktop = mb->vtop;
     265      404699 :         stk->blk = mb;
     266      404699 :         stk->workers = 0;
     267      404699 :         stk->memory = 0;
     268    91957218 :         initStack(0, res);
     269      404698 :         if(!res) {
     270           0 :                 freeStack(stk);
     271           0 :                 return NULL;
     272             :         }
     273             :         return stk;
     274             : }
     275             : 
     276      363975 : str runMAL(Client cntxt, MalBlkPtr mb, MalBlkPtr mbcaller, MalStkPtr env)
     277             : {
     278             :         MalStkPtr stk = NULL;
     279             :         int i;
     280             :         ValPtr lhs, rhs;
     281             :         str ret;
     282             :         (void) mbcaller;
     283             : 
     284             :         /* Prepare a new interpreter call. This involves two steps, (1)
     285             :          * allocate the minimum amount of stack space needed, some slack
     286             :          * resources are included to permit code optimizers to add a few
     287             :          * variables at run time, (2) copying the arguments into the new
     288             :          * stack frame.
     289             :          *
     290             :          * The env stackframe is set when a MAL function is called
     291             :          * recursively.  Alternatively, there is no caller but a stk to be
     292             :          * re-used for interpretation.  We assume here that it aligns with
     293             :          * the variable table of the routine being called.
     294             :          *
     295             :          * allocate space for value stack the global stack should be large
     296             :          * enough
     297             :          */
     298      363975 :         cntxt->lastcmd= time(0);
     299      363975 :         ATOMIC_SET(&cntxt->lastprint, GDKusec());
     300      363976 :         if (env != NULL) {
     301             :                 int res = 1;
     302             :                 stk = env;
     303        6214 :                 if (mb != stk->blk)
     304           0 :                         throw(MAL, "mal.interpreter","misalignment of symbols");
     305        6214 :                 if (mb->vtop > stk->stksize)
     306           0 :                         throw(MAL, "mal.interpreter","stack too small");
     307       18045 :                 initStack(env->stkbot, res);
     308        6214 :                 if(!res)
     309           0 :                         throw(MAL, "mal.interpreter", MAL_MALLOC_FAIL);
     310             :         } else {
     311      357762 :                 stk = prepareMALstack(mb, mb->vsize);
     312      357763 :                 if (stk == 0)
     313           0 :                         throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     314      357763 :                 stk->blk = mb;
     315      357763 :                 stk->cmd = cntxt->itrace;    /* set debug mode */
     316             :                 /*safeguardStack*/
     317             :                 if( env){
     318             :                         stk->stkdepth = stk->stksize + env->stkdepth;
     319             :                         stk->calldepth = env->calldepth + 1;
     320             :                         stk->up = env;
     321             :                         if (stk->calldepth > 256)
     322             :                                 throw(MAL, "mal.interpreter", MAL_CALLDEPTH_FAIL);
     323             :                 }
     324             :                 /*
     325             :                  * An optimization is to copy all constant variables used in
     326             :                  * functions immediately onto the value stack. Then we do not
     327             :                  * have to check for their location later on any more. At some
     328             :                  * point, the effect is optimal, if at least several constants
     329             :                  * are referenced in a function (a gain on tst400a of 20% has
     330             :                  * been observed due the small size of the function).
     331             :                  */
     332             :         }
     333      363977 :         if (stk->cmd && env && stk->cmd != 'f')
     334           0 :                 stk->cmd = env->cmd;
     335      363977 :         ret = runMALsequence(cntxt, mb, 1, 0, stk, env, 0);
     336             : 
     337             :         /* pass the new debug mode to the caller */
     338      363977 :         if (stk->cmd && env && stk->cmd != 'f')
     339           0 :                 env->cmd = stk->cmd;
     340      363977 :         if (!stk->keepAlive && garbageControl(getInstrPtr(mb, 0)))
     341      357763 :                 garbageCollector(cntxt, mb, stk, env != stk);
     342      363977 :         if (stk && stk != env)
     343      357763 :                 freeStack(stk);
     344      363977 :         if (ret == MAL_SUCCEED && cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout)
     345           0 :                 throw(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     346             :         return ret;
     347             : }
     348             : 
     349             : /* Single instruction
     350             :  * It is possible to re-enter the interpreter at a specific place.
     351             :  * This is used in the area where we need to support co-routines.
     352             :  *
     353             :  * A special case for MAL interpretation is to execute just one instruction.
     354             :  * This is typically used by optimizers and schedulers that need part of the
     355             :  * answer to direct their actions. Or, a dataflow scheduler could step in
     356             :  * to enforce a completely different execution order.
     357             :  */
     358     1065669 : str reenterMAL(Client cntxt, MalBlkPtr mb, int startpc, int stoppc, MalStkPtr stk)
     359             : {
     360             :         str ret;
     361             :         int keepAlive;
     362             : 
     363     1065669 :         if (stk == NULL)
     364           0 :                 throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     365     1065669 :         keepAlive = stk->keepAlive;
     366     1065669 :         ret = runMALsequence(cntxt, mb, startpc, stoppc, stk, 0, 0);
     367             : 
     368             :         /* pass the new debug mode to the caller */
     369     1065669 :         if (keepAlive == 0 && garbageControl(getInstrPtr(mb, 0)))
     370           0 :                 garbageCollector(cntxt, mb, stk, stk != 0);
     371             :         return ret;
     372             : }
     373             : 
     374             : /*
     375             :  * Front ends may benefit from a more direct call to any of the MAL
     376             :  * procedural abstractions. The argument list points to the arguments
     377             :  * for the block to be executed. An old stack frame may be re-used,
     378             :  * but it is then up to the caller to ensure it is properly
     379             :  * initialized.
     380             :  * The call does not return values, they are ignored.
     381             :  */
     382             : str
     383           0 : callMAL(Client cntxt, MalBlkPtr mb, MalStkPtr *env, ValPtr argv[], char debug)
     384             : {
     385             :         MalStkPtr stk = NULL;
     386             :         str ret = MAL_SUCCEED;
     387             :         int i;
     388             :         ValPtr lhs;
     389           0 :         InstrPtr pci = getInstrPtr(mb, 0);
     390             : 
     391           0 :         cntxt->lastcmd= time(0);
     392             : 
     393           0 :         switch (pci->token) {
     394           0 :         case FUNCTIONsymbol:
     395             :         case FCNcall:
     396             :                 /*
     397             :                  * Prepare the stack frame for this operation. Copy all the arguments
     398             :                  * in place. We assume that the caller has supplied pointers for
     399             :                  * all arguments and return values.
     400             :                  */
     401           0 :                 if (*env == NULL) {
     402           0 :                         stk = prepareMALstack(mb, mb->vsize);
     403           0 :                         if (stk == NULL)
     404           0 :                                 throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     405           0 :                         stk->up = 0;
     406           0 :                         *env = stk;
     407             :                 } else {
     408             :                         ValPtr lhs, rhs;
     409             :                         int res = 1;
     410             : 
     411             :                         stk = *env;
     412           0 :                         initStack(0, res);
     413           0 :                         if(!res)
     414           0 :                                 throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     415             :                 }
     416           0 :                 assert(stk);
     417           0 :                 for (i = pci->retc; i < pci->argc; i++) {
     418           0 :                         lhs = &stk->stk[pci->argv[i]];
     419           0 :                         if (VALcopy(lhs, argv[i]) == NULL)
     420           0 :                                 throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     421           0 :                         if (lhs->vtype == TYPE_bat)
     422           0 :                                 BBPretain(lhs->val.bval);
     423             :                 }
     424           0 :                 stk->cmd = debug;
     425           0 :                 ret = runMALsequence(cntxt, mb, 1, 0, stk, 0, 0);
     426             :                 break;
     427           0 :         case FACTORYsymbol:
     428             :         case FACcall:
     429           0 :                 ret = callFactory(cntxt, mb, argv, debug);
     430             :                 break;
     431           0 :         case PATcall:
     432             :         case CMDcall:
     433             :         default:
     434           0 :                 throw(MAL, "mal.interpreter", RUNTIME_UNKNOWN_INSTRUCTION);
     435             :         }
     436             :         if (stk)
     437           0 :                 garbageCollector(cntxt, mb, stk, TRUE);
     438           0 :         if ( ret == MAL_SUCCEED && cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout)
     439           0 :                 throw(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     440             :         return ret;
     441             : }
     442             : 
     443             : /*
     444             :  * The core of the interpreter is presented next. It takes the context
     445             :  * information and starts the interpretation at the designated
     446             :  * instruction.  Note that the stack frame is aligned and initialized
     447             :  * in the enclosing routine.  When we start executing the first
     448             :  * instruction, we take the wall-clock time for resource management.
     449             :  */
     450    18344457 : str runMALsequence(Client cntxt, MalBlkPtr mb, int startpc,
     451             :                                    int stoppc, MalStkPtr stk, MalStkPtr env, InstrPtr pcicaller)
     452             : {
     453             :         ValPtr lhs, rhs, v;
     454             :         int i, k;
     455             :         InstrPtr pci = 0;
     456             :         int exceptionVar;
     457    18344457 :         str ret = MAL_SUCCEED, localGDKerrbuf= GDKerrbuf;
     458             :         ValRecord backups[16];
     459             :         ValPtr backup;
     460             :         int garbages[16], *garbage;
     461             :         int stkpc = 0;
     462             :         RuntimeProfileRecord runtimeProfile, runtimeProfileFunction;
     463             :         lng lastcheck = 0;
     464             :         int     startedProfileQueue = 0;
     465             : #define CHECKINTERVAL 1000 /* how often do we check for client disconnect */
     466    18333057 :         runtimeProfile.ticks = runtimeProfileFunction.ticks = 0;
     467             : 
     468    18333057 :         if (stk == NULL)
     469           0 :                 throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     470             : 
     471             :         /* prepare extended backup and garbage structures */
     472    18333057 :         if (startpc+1 == stoppc) {
     473    16930284 :                 pci = getInstrPtr(mb, startpc);
     474    16930284 :                 if (pci->argc > 16) {
     475      129391 :                         backup = GDKmalloc(pci->argc * sizeof(ValRecord));
     476      129027 :                         garbage = (int*)GDKzalloc(pci->argc * sizeof(int));
     477      129115 :                         if( backup == NULL || garbage == NULL) {
     478           0 :                                 GDKfree(backup);
     479           0 :                                 GDKfree(garbage);
     480           0 :                                 throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     481             :                         }
     482             :                 } else {
     483             :                         backup = backups;
     484             :                         garbage = garbages;
     485    16800893 :                         memset(garbages, 0, sizeof(garbages));
     486             :                 }
     487     1402773 :         } else if ( mb->maxarg > 16 ){
     488      145594 :                 backup = GDKmalloc(mb->maxarg * sizeof(ValRecord));
     489      145594 :                 garbage = (int*)GDKzalloc(mb->maxarg * sizeof(int));
     490      145594 :                 if( backup == NULL || garbage == NULL) {
     491           0 :                         GDKfree(backup);
     492           0 :                         GDKfree(garbage);
     493           0 :                         throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     494             :                 }
     495             :         } else {
     496             :                 backup = backups;
     497             :                 garbage = garbages;
     498     1257179 :                 memset(garbages, 0, sizeof(garbages));
     499             :         }
     500             : 
     501             :         /* also produce event record for start of function */
     502    18332781 :         if ( startpc == 1 &&  startpc < mb->stop ){
     503             :                 startedProfileQueue = 1;
     504      402765 :                 runtimeProfileInit(cntxt, mb, stk);
     505      402774 :                 runtimeProfileBegin(cntxt, mb, stk, getInstrPtr(mb,0), &runtimeProfileFunction);
     506      402774 :                 mb->starttime = GDKusec();
     507      402774 :                 if (cntxt->sessiontimeout && mb->starttime - cntxt->session > cntxt->sessiontimeout) {
     508           0 :                         runtimeProfileFinish(cntxt, mb, stk);
     509           0 :                         if ( backup != backups) GDKfree(backup);
     510           0 :                         if ( garbage != garbages) GDKfree(garbage);
     511           0 :                         throw(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_SESSION_TIMEOUT);
     512             :                 }
     513             :         }
     514             :         stkpc = startpc;
     515             :         exceptionVar = -1;
     516             : 
     517    18332790 :         QryCtx qry_ctx = {.querytimeout=cntxt->querytimeout, .starttime=mb->starttime};
     518             : #ifndef NDEBUG
     519             :         /* very short timeout */
     520    18332790 :         QryCtx qry_ctx_abort = {.querytimeout=100, .starttime=mb->starttime};
     521             : #endif
     522             :         /* save, in case this function is called recursively */
     523    18332790 :         QryCtx *qry_ctx_save = MT_thread_get_qry_ctx();
     524    18330626 :         MT_thread_set_qry_ctx(&qry_ctx);
     525             : 
     526    82538637 :         while (stkpc < mb->stop && stkpc != stoppc) {
     527             :                 // incomplete block being executed, requires at least signature and end statement
     528    65234438 :                 MT_thread_setalgorithm(NULL);
     529    65227437 :                 pci = getInstrPtr(mb, stkpc);
     530    65227437 :                 if (cntxt->mode == FINISHCLIENT){
     531             :                         stkpc = stoppc;
     532           1 :                         if (ret == MAL_SUCCEED)
     533           1 :                                 ret= createException(MAL, "mal.interpreter", "prematurely stopped client");
     534             :                         break;
     535             :                 }
     536             : #ifndef NDEBUG
     537    65227436 :                 if (cntxt->itrace || stk->status) {
     538           1 :                         if (stk->status == 'p'){
     539             :                                 // execution is paused
     540           0 :                                 while ( stk->status == 'p')
     541           0 :                                         MT_sleep_ms(50);
     542           0 :                                 continue;
     543             :                         }
     544           1 :                         if ( stk->status == 'q')
     545           1 :                                 stk->cmd = 'x';
     546             : 
     547           1 :                         if (stk->cmd == 0)
     548           0 :                                 stk->cmd = cntxt->itrace;
     549           1 :                         mdbStep(cntxt, mb, stk, stkpc);
     550           1 :                         if (stk->cmd == 'x' ) {
     551           1 :                                 stk->cmd = 0;
     552           1 :                                 stkpc = mb->stop;
     553           1 :                                 MT_thread_set_qry_ctx(&qry_ctx_abort);
     554           1 :                                 ret= createException(MAL, "mal.interpreter", "prematurely stopped client");
     555           1 :                                 break;
     556             :                         }
     557             :                 }
     558             : #endif
     559             : 
     560             :                 //Ensure we spread system resources over multiple users as well.
     561    65227435 :                 runtimeProfileBegin(cntxt, mb, stk, pci, &runtimeProfile);
     562    65155871 :                 if (runtimeProfile.ticks > lastcheck + CHECKINTERVAL) {
     563    18338201 :                         if (cntxt->fdin && !mnstr_isalive(cntxt->fdin->s)) {
     564           0 :                                 cntxt->mode = FINISHCLIENT;
     565             :                                 stkpc = stoppc;
     566           0 :                                 ret= createException(MAL, "mal.interpreter", "prematurely stopped client");
     567           0 :                                 break;
     568             :                         }
     569    18293259 :                         lastcheck = runtimeProfile.ticks;
     570             :                 }
     571             : 
     572    65110929 :                 if (qptimeout > 0) {
     573           0 :                         lng t = GDKusec();
     574           0 :                         ATOMIC_BASE_TYPE lp = ATOMIC_GET(&cntxt->lastprint);
     575           0 :                         if ((lng) lp + qptimeout < t) {
     576             :                                 /* if still the same, replace lastprint with current
     577             :                                  * time and print the query */
     578           0 :                                 if (ATOMIC_CAS(&cntxt->lastprint, &lp, t)) {
     579           0 :                                         const char *q = cntxt->query ? cntxt->query : NULL;
     580           0 :                                         TRC_INFO(MAL_SERVER, "%s: query already running "LLFMT"s: %.200s\n",
     581             :                                                         cntxt->mythread->name,
     582             :                                                         (lng) (time(0) - cntxt->lastcmd),
     583             :                                                         q ? q : "");
     584             :                                 }
     585             :                         }
     586             :                 }
     587             : 
     588             :                 /* The interpreter loop
     589             :                  * The interpreter is geared towards execution a MAL
     590             :                  * procedure together with all its descendant
     591             :                  * invocations. As such, it provides the MAL abtract
     592             :                  * machine processor.
     593             :                  *
     594             :                  * The value-stack frame of the surrounding scope is
     595             :                  * needed to resolve binding values.  Getting (putting) a
     596             :                  * value from (into) a surrounding scope should be guarded
     597             :                  * with the exclusive access lock.  This situation is
     598             :                  * encapsulated by a bind() function call, whose
     599             :                  * parameters contain the access mode required.
     600             :                  *
     601             :                  * The formal procedure arguments are assumed to always
     602             :                  * occupy the first elements in the value stack.
     603             :                  *
     604             :                  * Before we execute an instruction the variables to be
     605             :                  * garbage collected are identified. In the post-execution
     606             :                  * phase they are removed.
     607             :                  */
     608   131469358 :                 for (i = 0; i < pci->retc; i++)
     609    66358429 :                         backup[i] = stk->stk[getArg(pci, i)];
     610             : 
     611    65110929 :                 if (garbageControl(pci)) {
     612   167532073 :                         for (i = 0; i < pci->argc; i++) {
     613   131562578 :                                 int a = getArg(pci, i);
     614             : 
     615   131562578 :                                 if (stk->stk[a].vtype == TYPE_bat && getEndScope(mb, a) == stkpc && isNotUsedIn(pci, i + 1, a))
     616    14682892 :                                         garbage[i] = a;
     617             :                                 else
     618   116870593 :                                         garbage[i] = -1;
     619             :                         }
     620             :                 }
     621             : 
     622    65101836 :                 freeException(ret);
     623             :                 ret = MAL_SUCCEED;
     624    65131701 :                 switch (pci->token) {
     625     3502047 :                 case ASSIGNsymbol:
     626             :                         /* Assignment command
     627             :                          * The assignment statement copies values around on
     628             :                          * the stack frame, including multiple assignments.
     629             :                          *
     630             :                          * Pushing constants/initial values onto the stack is
     631             :                          * a separate operation.  It takes the constant value
     632             :                          * discovered at compile time and stored in the symbol
     633             :                          * table and moves it to the stackframe location. This
     634             :                          * activity is made part of the start-up procedure.
     635             :                          *
     636             :                          * The before after calls should be reconsidered here,
     637             :                          * because their. They seem superflous and the way
     638             :                          * they are used will cause errors in multi-assignment
     639             :                          * statements.
     640             :                          */
     641     5960598 :                         for (k = 0, i = pci->retc; k < pci->retc && i < pci->argc; i++, k++) {
     642     2458548 :                                 lhs = &stk->stk[pci->argv[k]];
     643     2458548 :                                 rhs = &stk->stk[pci->argv[i]];
     644     2458548 :                                 if(VALcopy(lhs, rhs) == NULL) {
     645           0 :                                         ret = createException(MAL, "mal.interpreter", MAL_MALLOC_FAIL);
     646           0 :                                         break;
     647     2458547 :                                 } else if (lhs->vtype == TYPE_bat && !is_bat_nil(lhs->val.bval))
     648        1943 :                                         BBPretain(lhs->val.bval);
     649             :                         }
     650             :                         break;
     651    18329292 :                 case PATcall:
     652    18329292 :                         if (pci->fcn == NULL) {
     653           0 :                                 ret = createException(MAL,"mal.interpreter", "address of pattern %s.%s missing", pci->modname, pci->fcnname);
     654             :                         } else {
     655    18329292 :                                 TRC_DEBUG(ALGO, "calling %s.%s\n", pci->modname ? pci->modname : "<null>", pci->fcnname ? pci->fcnname : "<null>");
     656    18329292 :                                 ret = (*pci->fcn)(cntxt, mb, stk, pci);
     657             : #ifndef NDEBUG
     658    18363391 :                                 if (ret == MAL_SUCCEED) {
     659             :                                         /* check that the types of actual results match
     660             :                                          * expected results */
     661    37929297 :                                         for (i = 0; i < pci->retc; i++) {
     662    19500921 :                                                 int a = getArg(pci, i);
     663    19500921 :                                                 int t = getArgType(mb, pci, i);
     664             : 
     665    19500921 :                                                 if (isaBatType(t)) {
     666     7898613 :                                                         bat bid = stk->stk[a].val.bval;
     667     7898613 :                                                         BAT *_b = BATdescriptor(bid);
     668     7908221 :                                                         t = getBatType(t);
     669     7908221 :                                                         assert(stk->stk[a].vtype == TYPE_bat);
     670    23182229 :                                                         assert(is_bat_nil(bid) ||
     671             :                                                                    t == TYPE_any ||
     672             :                                                                    ATOMtype(_b->ttype) == ATOMtype(t));
     673     7908221 :                                                         if(_b) BBPunfix(bid);
     674             :                                                 } else {
     675    11602308 :                                                         assert(t == stk->stk[a].vtype);
     676             :                                                 }
     677             :                                         }
     678             :                                 }
     679             : #endif
     680             :                         }
     681             :                         break;
     682    41893175 :                 case CMDcall:
     683    41893175 :                         TRC_DEBUG(ALGO, "calling %s.%s\n", pci->modname ? pci->modname : "<null>", pci->fcnname ? pci->fcnname : "<null>");
     684    41893175 :                         ret = malCommandCall(stk, pci);
     685             : #ifndef NDEBUG
     686    41868458 :                         if (ret == MAL_SUCCEED) {
     687             :                                 /* check that the types of actual results match
     688             :                                  * expected results */
     689    84502924 :                                 for (i = 0; i < pci->retc; i++) {
     690    42605026 :                                         int a = getArg(pci, i);
     691    42605026 :                                         int t = getArgType(mb, pci, i);
     692             : 
     693    42605026 :                                         if (isaBatType(t)) {
     694             :                                                 //bat bid = stk->stk[a].val.bval;
     695    25160557 :                                                 t = getBatType(t);
     696    25160557 :                                                 assert(stk->stk[a].vtype == TYPE_bat);
     697             :                                                 //assert( !is_bat_nil(bid));
     698    25160557 :                                                 assert(t != TYPE_any);
     699             :                                                 //assert( ATOMtype(BBP_desc(bid)->ttype) == ATOMtype(t));
     700             :                                         } else {
     701    17444469 :                                                 assert(t == stk->stk[a].vtype);
     702             :                                         }
     703             :                                 }
     704             :                         }
     705             : #endif
     706             :                         break;
     707     1000025 :                 case FACcall:
     708             :                         /*
     709             :                          * Factory calls are more involved. At this stage it
     710             :                          * is a synchrononous call to the factory manager.
     711             :                          * Factory calls should deal with the reference
     712             :                          * counting.
     713             :                          */
     714     1000025 :                         if (pci->blk == NULL)
     715           0 :                                 ret = createException(MAL,"mal.interpreter", "%s.%s[%d] reference to MAL function missing", getModuleId(pci), getFunctionId(pci), pci->pc);
     716             :                         else {
     717             :                                 /* show call before entering the factory */
     718             : #ifndef NDEBUG
     719     1000025 :                                 if (cntxt->itrace) {
     720           0 :                                         if (stk->cmd == 0)
     721           0 :                                                 stk->cmd = cntxt->itrace;
     722           0 :                                         mdbStep(cntxt, pci->blk, stk, 0);
     723           0 :                                         if (stk->cmd == 'x') {
     724           0 :                                                 stk->cmd = 0;
     725           0 :                                                 stkpc = mb->stop;
     726             :                                         }
     727             :                                 }
     728             : #endif
     729     1000025 :                                 ret = runFactory(cntxt, pci->blk, mb, stk, pci);
     730             :                         }
     731             :                         break;
     732       38744 :                 case FCNcall:
     733             :                         /*
     734             :                          * MAL function calls are relatively expensive,
     735             :                          * because they have to assemble a new stack frame and
     736             :                          * do housekeeping, such as garbagecollection of all
     737             :                          * non-returned values.
     738             :                          */
     739             :                         {       MalStkPtr nstk;
     740             :                                 InstrPtr q;
     741             :                                 int ii, arg;
     742             : 
     743       38744 :                                 stk->pcup = stkpc;
     744       38744 :                                 nstk = prepareMALstack(pci->blk, pci->blk->vsize);
     745       38742 :                                 if (nstk == 0){
     746           0 :                                         ret= createException(MAL,"mal.interpreter",MAL_STACK_FAIL);
     747           0 :                                         break;
     748             :                                 }
     749             : 
     750             :                                 /*safeguardStack*/
     751       38742 :                                 nstk->stkdepth = nstk->stksize + stk->stkdepth;
     752       38742 :                                 nstk->calldepth = stk->calldepth + 1;
     753       38742 :                                 nstk->up = stk;
     754       38742 :                                 if (nstk->calldepth > 256) {
     755           1 :                                         ret= createException(MAL, "mal.interpreter", MAL_CALLDEPTH_FAIL);
     756           1 :                                         GDKfree(nstk);
     757           1 :                                         break;
     758             :                                 }
     759       38741 :                                 if ((unsigned)nstk->stkdepth > THREAD_STACK_SIZE / sizeof(mb->var[0]) / 4 && THRhighwater()){
     760             :                                         /* we are running low on stack space */
     761           0 :                                         ret= createException(MAL, "mal.interpreter", MAL_STACK_FAIL);
     762           0 :                                         GDKfree(nstk);
     763           0 :                                         break;
     764             :                                 }
     765             : 
     766             :                                 /* copy arguments onto destination stack */
     767       38741 :                                 q= getInstrPtr(pci->blk,0);
     768       38741 :                                 arg = q->retc;
     769      134540 :                                 for (ii = pci->retc; ii < pci->argc; ii++,arg++) {
     770       95791 :                                         lhs = &nstk->stk[q->argv[arg]];
     771       95791 :                                         rhs = &stk->stk[pci->argv[ii]];
     772       95791 :                                         if(VALcopy(lhs, rhs) == NULL) {
     773           0 :                                                 GDKfree(nstk);
     774           0 :                                                 ret = createException(MAL, "mal.interpreter", MAL_MALLOC_FAIL);
     775           0 :                                                 break;
     776       95799 :                                         } else if (lhs->vtype == TYPE_bat)
     777         187 :                                                 BBPretain(lhs->val.bval);
     778             :                                 }
     779       38749 :                                 if (ret == MAL_SUCCEED && ii == pci->argc) {
     780       38750 :                                         ret = runMALsequence(cntxt, pci->blk, 1, pci->blk->stop, nstk, stk, pci);
     781       38752 :                                         garbageCollector(cntxt, pci->blk, nstk, 0);
     782       38752 :                                         arg = q->retc;
     783      134557 :                                         for (ii = pci->retc; ii < pci->argc; ii++,arg++) {
     784       95805 :                                                 lhs = &nstk->stk[q->argv[arg]];
     785       95805 :                                                 if (lhs->vtype == TYPE_bat)
     786           0 :                                                         BBPrelease(lhs->val.bval);
     787             :                                         }
     788       38752 :                                         GDKfree(nstk);
     789             :                                 }
     790             :                         }
     791             :                         break;
     792             :                 case NOOPsymbol:
     793             :                 case REMsymbol:
     794             :                         break;
     795      368303 :                 case ENDsymbol:
     796      368303 :                         if (getInstrPtr(mb, 0)->token == FACTORYsymbol)
     797           0 :                                 ret = shutdownFactory(cntxt, mb);
     798      368303 :                         runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
     799      368304 :                         runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb,0), &runtimeProfileFunction);
     800      368303 :                         if (pcicaller && garbageControl(getInstrPtr(mb, 0)))
     801        5942 :                                 garbageCollector(cntxt, mb, stk, TRUE);
     802      368303 :                         if (cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout){
     803           0 :                                 freeException(ret); /* overrule exception */
     804           0 :                                 ret= createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     805           0 :                                 break;
     806             :                         }
     807      368303 :                         stkpc = mb->stop;    // force end of loop
     808      368303 :                         continue;
     809           0 :                 default: {
     810             :                         str w;
     811           0 :                         if (pci->token < 0) {
     812             :                                 /* temporary NOOP instruction */
     813             :                                 break;
     814             :                         }
     815           0 :                         w= instruction2str(mb, 0, pci, FALSE);
     816           0 :                         if(w) {
     817           0 :                                 ret = createException(MAL,"interpreter", "unkown operation:%s", w);
     818           0 :                                 GDKfree(w);
     819             :                         } else {
     820           0 :                                 ret = createException(MAL,"interpreter", "failed instruction2str");
     821             :                         }
     822             :                         // runtimeProfileBegin already sets the time in the instruction
     823           0 :                         if (cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout){
     824           0 :                                 freeException(ret);     /* in case it's set */
     825           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     826           0 :                                 break;
     827             :                         }
     828             : 
     829           0 :                         stkpc= mb->stop;
     830           0 :                         continue;
     831             :                 }       }
     832             : 
     833             :                 /* monitoring information should reflect the input arguments,
     834             :                    which may be removed by garbage collection  */
     835             :                 /* BEWARE, the SQL engine or MAL function could zap the block, leaving garbage behind in pci */
     836             :                 /* this hack means we loose a closing event */
     837    64827928 :                 if( mb->stop <= 1)
     838           0 :                         continue;
     839    64827928 :                 runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
     840             :                 /* check for strong debugging after each MAL statement */
     841             :                 /* when we find a timeout situation, then the result is already known
     842             :                  * and assigned,  the backup version is not removed*/
     843    64708252 :                 if ( pci->token != FACcall && ret== MAL_SUCCEED) {
     844   129277319 :                         for (i = 0; i < pci->retc; i++) {
     845    65533495 :                                 lhs = &backup[i];
     846    98522892 :                                 if (BATatoms[lhs->vtype].atomUnfix &&
     847    32961433 :                                         (*BATatoms[lhs->vtype].atomUnfix)(VALget(lhs)) != GDK_SUCCEED) {
     848           0 :                                         ret = createException(MAL, "mal.propertyCheck", GDK_EXCEPTION);
     849             :                                 }
     850    65561459 :                                 if (ATOMextern(lhs->vtype) &&
     851      937871 :                                         lhs->val.pval &&
     852      101334 :                                         lhs->val.pval != ATOMnilptr(lhs->vtype) &&
     853      101334 :                                         lhs->val.pval != stk->stk[getArg(pci, i)].val.pval)
     854      100806 :                                         GDKfree(lhs->val.pval);
     855             :                         }
     856    63743824 :                         if (GDKdebug & (CHECKMASK|PROPMASK) && exceptionVar < 0) {
     857             :                                 BAT *b;
     858             : 
     859   128786840 :                                 for (i = 0; i < pci->retc; i++) {
     860    65288199 :                                         if (garbage[i] == -1 && stk->stk[getArg(pci, i)].vtype == TYPE_bat &&
     861    32479008 :                                                 !is_bat_nil(stk->stk[getArg(pci, i)].val.bval)) {
     862    32482652 :                                                 assert(stk->stk[getArg(pci, i)].val.bval > 0);
     863    32482652 :                                                 b = BBPquickdesc(stk->stk[getArg(pci, i)].val.bval);
     864    32419931 :                                                 if (b == NULL) {
     865           0 :                                                         if (ret == MAL_SUCCEED)
     866           0 :                                                                 ret = createException(MAL, "mal.propertyCheck", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     867           0 :                                                         continue;
     868             :                                                 }
     869    32419931 :                                                 b = BATdescriptor(stk->stk[getArg(pci, i)].val.bval);
     870    32505920 :                                                 if (b) {
     871    32508082 :                                                         BATassertProps(b);
     872    32504580 :                                                         BBPunfix(b->batCacheid);
     873             :                                                 }
     874             :                                         }
     875             :                                 }
     876             :                         }
     877             : 
     878             :                         /* general garbage collection */
     879    63768674 :                         if (ret == MAL_SUCCEED && garbageControl(pci)) {
     880   167971323 :                                 for (i = 0; i < pci->argc; i++) {
     881   131880850 :                                         int a = getArg(pci, i);
     882             : 
     883   131880850 :                                         if (isaBatType(getArgType(mb, pci, i))) {
     884             :                                                 bat bid = stk->stk[a].val.bval;
     885             : 
     886    79704327 :                                                 if (garbage[i] >= 0) {
     887    14661329 :                                                         bid = stk->stk[garbage[i]].val.bval;
     888    14661329 :                                                         stk->stk[garbage[i]].val.bval = bat_nil;
     889    14661329 :                                                         BBPcold(bid);
     890    14654361 :                                                         BBPrelease(bid);
     891             :                                                 }
     892             :                                         }
     893             :                                 }
     894             :                         }
     895             :                 }
     896             : 
     897             :                 /* Exception handling */
     898    64809704 :                 if (localGDKerrbuf && localGDKerrbuf[0]) {
     899           2 :                         if( ret == MAL_SUCCEED)
     900           2 :                                 ret = createException(MAL,"mal.interpreter",GDK_EXCEPTION);
     901             :                         // TODO take properly care of the GDK exception
     902           2 :                         localGDKerrbuf[0]=0;
     903             :                 }
     904             : 
     905    64809704 :                 if (ret != MAL_SUCCEED) {
     906             :                         str msg = 0;
     907             : 
     908             : #ifndef NDEBUG
     909        2926 :                         if (stk->cmd) {
     910           0 :                                 mnstr_printf(cntxt->fdout, "!ERROR: %s\n", ret);
     911           0 :                                 stk->cmd = '\n'; /* in debugging go to step mode */
     912           0 :                                 mdbStep(cntxt, mb, stk, stkpc);
     913           0 :                                 if (stk->cmd == 'x' || stk->cmd == 'q' ) {
     914           0 :                                         stkpc = mb->stop;
     915           0 :                                         continue;
     916             :                                 }
     917           0 :                                 if (stk->cmd == 'r') {
     918           0 :                                         stk->cmd = 'n';
     919             :                                         stkpc = startpc;
     920             :                                         exceptionVar = -1;
     921           0 :                                         continue;
     922             :                                 }
     923             :                         }
     924             : #endif
     925             :                         /* Detect any exception received from the implementation. */
     926             :                         /* The first identifier is an optional exception name */
     927        2926 :                         if (strstr(ret, "!skip-to-end")) {
     928           0 :                                 freeException(ret);
     929             :                                 ret = MAL_SUCCEED;
     930           0 :                                 stkpc = mb->stop;
     931           0 :                                 continue;
     932             :                         }
     933             :                         /*
     934             :                          * Exceptions are caught based on their name, which is part of the
     935             :                          * exception message. The ANYexception variable catches all.
     936             :                          */
     937             :                         exceptionVar = -1;
     938        2926 :                         msg = strchr(ret, ':');
     939        2926 :                         if (msg) {
     940        2926 :                                 exceptionVar = findVariableLength(mb, ret, (int)(msg - ret));
     941             :                         }
     942        2926 :                         if (exceptionVar == -1)
     943        2913 :                                 exceptionVar = findVariable(mb, "ANYexception");
     944             : 
     945             :                         /* unknown exceptions lead to propagation */
     946        2926 :                         if (exceptionVar == -1) {
     947        2913 :                                 if (cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout) {
     948           3 :                                         freeException(ret);
     949           3 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     950             :                                 }
     951        2913 :                                 stkpc = mb->stop;
     952        2913 :                                 continue;
     953             :                         }
     954             :                         /* assure correct variable type */
     955          13 :                         if (getVarType(mb, exceptionVar) == TYPE_str) {
     956             :                                 /* watch out for concurrent access */
     957          13 :                                 MT_lock_set(&mal_contextLock);
     958             :                                 v = &stk->stk[exceptionVar];
     959          13 :                                 if (v->val.sval)
     960           3 :                                         freeException(v->val.sval);    /* old exception*/
     961          13 :                                 v->vtype = TYPE_str;
     962          13 :                                 v->val.sval = ret;
     963          13 :                                 v->len = strlen(v->val.sval);
     964             :                                 ret = MAL_SUCCEED;
     965          13 :                                 MT_lock_unset(&mal_contextLock);
     966             :                         } else {
     967           0 :                                 mnstr_printf(cntxt->fdout, "%s", ret);
     968           0 :                                 freeException(ret);
     969             :                                 ret = MAL_SUCCEED;
     970             :                         }
     971             :                         /* position yourself at the catch instruction for further decisions */
     972             :                         /* skipToCatch(exceptionVar,@2,@3) */
     973             : #ifndef NDEBUG
     974          13 :                         if (stk->cmd == 'C') {
     975           0 :                                 stk->cmd = 'n';
     976           0 :                                 mdbStep(cntxt, mb, stk, stkpc);
     977           0 :                                 if (stk->cmd == 'x' ) {
     978           0 :                                         stkpc = mb->stop;
     979           0 :                                         continue;
     980             :                                 }
     981             :                         }
     982             : #endif
     983             :                         /* skip to catch block or end */
     984         103 :                         for (; stkpc < mb->stop; stkpc++) {
     985         103 :                                 InstrPtr l = getInstrPtr(mb, stkpc);
     986         103 :                                 if (l->barrier == CATCHsymbol) {
     987             :                                         int j;
     988          23 :                                         for (j = 0; j < l->retc; j++)
     989          18 :                                                 if (getArg(l, j) == exceptionVar)
     990             :                                                         break;
     991           5 :                                                 else if (strcmp(getArgName(mb, l, j), "ANYexception") == 0)
     992             :                                                         break;
     993          18 :                                         if (j < l->retc)
     994             :                                                 break;
     995             :                                 }
     996             :                         }
     997          13 :                         if (stkpc == mb->stop) {
     998           0 :                                 if (cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout){
     999           0 :                                         freeException(ret);
    1000           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
    1001           0 :                                         stkpc = mb->stop;
    1002             :                                 }
    1003           0 :                                 continue;
    1004             :                         }
    1005          13 :                         pci = getInstrPtr(mb, stkpc);
    1006             :                 }
    1007             : 
    1008             :                 /*
    1009             :                  * After the expression has been evaluated we should check for
    1010             :                  * a possible change in the control flow.
    1011             :                  */
    1012    64806791 :                 switch (pci->barrier) {
    1013      703574 :                 case BARRIERsymbol:
    1014      703574 :                         v = &stk->stk[getDestVar(pci)];
    1015             :                         /* skip to end of barrier, depends on the type */
    1016      703574 :                         switch (v->vtype) {
    1017      703055 :                         case TYPE_bit:
    1018      703055 :                                 if (v->val.btval == FALSE || is_bit_nil(v->val.btval))
    1019      659066 :                                         stkpc = pci->jump;
    1020             :                                 break;
    1021           0 :                         case TYPE_bte:
    1022           0 :                                 if (is_bte_nil(v->val.btval))
    1023           0 :                                         stkpc = pci->jump;
    1024             :                                 break;
    1025         487 :                         case TYPE_oid:
    1026         487 :                                 if (is_oid_nil(v->val.oval))
    1027         371 :                                         stkpc = pci->jump;
    1028             :                                 break;
    1029           0 :                         case TYPE_sht:
    1030           0 :                                 if (is_sht_nil(v->val.shval))
    1031           0 :                                         stkpc = pci->jump;
    1032             :                                 break;
    1033          10 :                         case TYPE_int:
    1034          10 :                                 if (is_int_nil(v->val.ival))
    1035           0 :                                         stkpc = pci->jump;
    1036             :                                 break;
    1037          15 :                         case TYPE_lng:
    1038          15 :                                 if (is_lng_nil(v->val.lval))
    1039           0 :                                         stkpc = pci->jump;
    1040             :                                 break;
    1041             : #ifdef HAVE_HGE
    1042           0 :                         case TYPE_hge:
    1043           0 :                                 if (is_hge_nil(v->val.hval))
    1044           0 :                                         stkpc = pci->jump;
    1045             :                                 break;
    1046             : #endif
    1047           1 :                         case TYPE_flt:
    1048           1 :                                 if (is_flt_nil(v->val.fval))
    1049           0 :                                         stkpc = pci->jump;
    1050             :                                 break;
    1051           0 :                         case TYPE_dbl:
    1052           0 :                                 if (is_dbl_nil(v->val.dval))
    1053           0 :                                         stkpc = pci->jump;
    1054             :                                 break;
    1055           0 :                         case TYPE_str:
    1056           0 :                                 if (strNil(v->val.sval))
    1057           0 :                                         stkpc = pci->jump;
    1058             :                                 break;
    1059           6 :                         default:
    1060           6 :                                 ret = createException(MAL,"mal.interpreter", "%s: Unknown barrier type", getVarName(mb, getDestVar(pci)));
    1061             :                         }
    1062      703574 :                         stkpc++;
    1063      703574 :                         break;
    1064    17200574 :                 case LEAVEsymbol:
    1065             :                 case REDOsymbol:
    1066    17200574 :                         v = &stk->stk[getDestVar(pci)];
    1067             :                         /* skip to end of barrier, depending on the type */
    1068    17200574 :                         switch (v->vtype) {
    1069     1000850 :                         case TYPE_bit:
    1070     1000850 :                                 if (v->val.btval == TRUE )
    1071     1000440 :                                         stkpc = pci->jump;
    1072             :                                 else
    1073         410 :                                         stkpc++;
    1074             :                                 break;
    1075           0 :                         case TYPE_str:
    1076           0 :                                 if (!strNil(v->val.sval))
    1077           0 :                                         stkpc = pci->jump;
    1078             :                                 else
    1079           0 :                                         stkpc++;
    1080             :                                 break;
    1081       25877 :                         case TYPE_oid:
    1082       25877 :                                 if (!is_oid_nil(v->val.oval))
    1083       25766 :                                         stkpc = pci->jump;
    1084             :                                 else
    1085         111 :                                         stkpc++;
    1086             :                                 break;
    1087           0 :                         case TYPE_sht:
    1088           0 :                                 if (!is_sht_nil(v->val.shval))
    1089           0 :                                         stkpc = pci->jump;
    1090             :                                 else
    1091           0 :                                         stkpc++;
    1092             :                                 break;
    1093     1963592 :                         case TYPE_int:
    1094     1963592 :                                 if (!is_int_nil(v->val.ival))
    1095     1963587 :                                         stkpc = pci->jump;
    1096             :                                 else
    1097           5 :                                         stkpc++;
    1098             :                                 break;
    1099           0 :                         case TYPE_bte:
    1100           0 :                                 if (!is_bte_nil(v->val.btval))
    1101           0 :                                         stkpc = pci->jump;
    1102             :                                 else
    1103           0 :                                         stkpc++;
    1104             :                                 break;
    1105    14210253 :                         case TYPE_lng:
    1106    14210253 :                                 if (!is_lng_nil(v->val.lval))
    1107    14210238 :                                         stkpc = pci->jump;
    1108             :                                 else
    1109          15 :                                         stkpc++;
    1110             :                                 break;
    1111             : #ifdef HAVE_HGE
    1112           0 :                         case TYPE_hge:
    1113           0 :                                 if (!is_hge_nil(v->val.hval))
    1114           0 :                                         stkpc = pci->jump;
    1115             :                                 else
    1116           0 :                                         stkpc++;
    1117             :                                 break;
    1118             : #endif
    1119           2 :                         case TYPE_flt:
    1120           2 :                                 if (!is_flt_nil(v->val.fval))
    1121           1 :                                         stkpc = pci->jump;
    1122             :                                 else
    1123           1 :                                         stkpc++;
    1124             :                                 break;
    1125           0 :                         case TYPE_dbl:
    1126           0 :                                 if (!is_dbl_nil(v->val.dval))
    1127           0 :                                         stkpc = pci->jump;
    1128             :                                 else
    1129           0 :                                         stkpc++;
    1130             :                                 break;
    1131             :                         default:
    1132             :                                 break;
    1133             :                         }
    1134             :                         break;
    1135          31 :                 case CATCHsymbol:
    1136             :                         /* catch blocks are skipped unless
    1137             :                            searched for explicitly*/
    1138          31 :                         if (exceptionVar < 0) {
    1139          15 :                                 stkpc = pci->jump;
    1140          15 :                                 break;
    1141             :                         }
    1142             :                         exceptionVar = -1;
    1143          16 :                         stkpc++;
    1144          16 :                         break;
    1145       44023 :                 case EXITsymbol:
    1146       44023 :                         if (getDestVar(pci) == exceptionVar)
    1147             :                                 exceptionVar = -1;
    1148       44023 :                         stkpc++;
    1149       44023 :                         break;
    1150           6 :                 case RAISEsymbol:
    1151           6 :                         exceptionVar = getDestVar(pci);
    1152             :                         //freeException(ret);
    1153             :                         ret = MAL_SUCCEED;
    1154           6 :                         if (getVarType(mb, getDestVar(pci)) == TYPE_str) {
    1155             :                                 char nme[256];
    1156           4 :                                 snprintf(nme,256,"%s.%s[%d]", getModuleId(getInstrPtr(mb,0)), getFunctionId(getInstrPtr(mb,0)), stkpc);
    1157           4 :                                 ret = createException(MAL, nme, "%s", stk->stk[getDestVar(pci)].val.sval);
    1158             :                         }
    1159             :                         /* skipToCatch(exceptionVar, @2, stk) */
    1160             : #ifndef NDEBUG
    1161           6 :                         if (stk->cmd == 'C') {
    1162           0 :                                 stk->cmd = 'n';
    1163           0 :                                 mdbStep(cntxt, mb, stk, stkpc);
    1164           0 :                                 if (stk->cmd == 'x' ) {
    1165           0 :                                         stkpc = mb->stop;
    1166           0 :                                         continue;
    1167             :                                 }
    1168             :                         }
    1169             : #endif
    1170             :                         /* skip to catch block or end */
    1171          22 :                         for (; stkpc < mb->stop; stkpc++) {
    1172          19 :                                 InstrPtr l = getInstrPtr(mb, stkpc);
    1173          19 :                                 if (l->barrier == CATCHsymbol) {
    1174             :                                         int j;
    1175           3 :                                         for (j = 0; j < l->retc; j++)
    1176           3 :                                                 if (getArg(l, j) == exceptionVar)
    1177             :                                                         break;
    1178           0 :                                                 else if (strcmp(getArgName(mb, l, j), "ANYexception") == 0)
    1179             :                                                         break;
    1180           3 :                                         if (j < l->retc)
    1181             :                                                 break;
    1182             :                                 }
    1183             :                         }
    1184           6 :                         if (stkpc == mb->stop) {
    1185           3 :                                 runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
    1186           3 :                                 runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb,0), &runtimeProfileFunction);
    1187           3 :                                 break;
    1188             :                         }
    1189             :                         if (stkpc == mb->stop)
    1190             :                                 ret = mb->errors = createMalException(mb, stkpc, TYPE,
    1191             :                                         "Exception raised\n");
    1192             :                         break;
    1193     1000022 :                 case YIELDsymbol:     /* to be defined */
    1194     1000022 :                         if( startedProfileQueue)
    1195          12 :                                 runtimeProfileFinish(cntxt, mb, stk);
    1196     1000022 :                         if ( backup != backups) GDKfree(backup);
    1197     1000022 :                         if ( garbage != garbages) GDKfree(garbage);
    1198     1000022 :                         ret = yieldFactory(mb, pci, stkpc);
    1199     1000022 :                         MT_thread_set_qry_ctx(qry_ctx_save);
    1200     1000022 :                         return ret;
    1201       32449 :                 case RETURNsymbol:
    1202             :                         /* Return from factory involves cleanup */
    1203             : 
    1204       32449 :                         if (getInstrPtr(mb, 0)->token == FACTORYsymbol) {
    1205           3 :                                 yieldResult(mb, pci, stkpc);
    1206           3 :                                 shutdownFactory(cntxt, mb);
    1207             :                         } else {
    1208             :                                 /* a fake multi-assignment */
    1209       32446 :                                 if (env != NULL && pcicaller != NULL) {
    1210             :                                         InstrPtr pp = pci;
    1211             :                                         pci = pcicaller;
    1212       65449 :                                         for (i = 0; i < pci->retc; i++) {
    1213       33000 :                                                 rhs = &stk->stk[pp->argv[i]];
    1214       33000 :                                                 lhs = &env->stk[pci->argv[i]];
    1215       33000 :                                                 if(VALcopy(lhs, rhs) == NULL) {
    1216           0 :                                                         ret = createException(MAL, "mal.interpreter", MAL_MALLOC_FAIL);
    1217           0 :                                                         break;
    1218       33002 :                                                 } else if (lhs->vtype == TYPE_bat)
    1219        1071 :                                                         BBPretain(lhs->val.bval);
    1220             :                                         }
    1221       32449 :                                         if (garbageControl(getInstrPtr(mb, 0)))
    1222       32408 :                                                 garbageCollector(cntxt, mb, stk, TRUE);
    1223             :                                         /* reset the clock */
    1224       32452 :                                         runtimeProfileExit(cntxt, mb, stk, pp, &runtimeProfile);
    1225       32449 :                                         runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb,0), &runtimeProfileFunction);
    1226             :                                 }
    1227             :                         }
    1228       32451 :                         stkpc = mb->stop;
    1229       32451 :                         continue;
    1230    45826112 :                 default:
    1231    45826112 :                         stkpc++;
    1232             :                 }
    1233    63774320 :                 if (cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout){
    1234           2 :                         if (ret == MAL_SUCCEED)
    1235           2 :                                 ret= createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
    1236           2 :                         stkpc= mb->stop;
    1237             :                 }
    1238             :         }
    1239    17304201 :         MT_thread_set_qry_ctx(qry_ctx_save);
    1240             : 
    1241             :         /* if we could not find the exception variable, cascade a new one */
    1242    17301952 :         if (exceptionVar >= 0) {
    1243             :                 char nme[256];
    1244           3 :                 snprintf(nme,256,"%s.%s[%d]", getModuleId(getInstrPtr(mb,0)), getFunctionId(getInstrPtr(mb,0)), stkpc);
    1245           3 :                 if (ret != MAL_SUCCEED) {
    1246             :                         str new, n;
    1247           2 :                         n = createException(MAL,nme,"exception not caught");
    1248             :                         if (n) {
    1249           2 :                                 new = GDKzalloc(strlen(ret) + strlen(n) +16);
    1250           2 :                                 if (new){
    1251           2 :                                         strcpy(new, ret);
    1252           2 :                                         if( new[strlen(new)-1] != '\n')
    1253           1 :                                                 strcat(new,"\n");
    1254           2 :                                         strcat(new,"!");
    1255           2 :                                         strcat(new,n);
    1256           2 :                                         freeException(n);
    1257           2 :                                         freeException(ret);
    1258             :                                         ret = new;
    1259             :                                 } else {
    1260           0 :                                         freeException(ret);
    1261             :                                         ret = n;
    1262             :                                 }
    1263             :                         }
    1264             :                 } else {
    1265           1 :                         ret = createException(MAL, nme, "Exception not caught");
    1266             :                 }
    1267             :         }
    1268    17301952 :         if( startedProfileQueue)
    1269      402754 :                 runtimeProfileFinish(cntxt, mb, stk);
    1270    17301960 :         if ( backup != backups) GDKfree(backup);
    1271    17310196 :         if ( garbage != garbages) GDKfree(garbage);
    1272             :         return ret;
    1273             : }
    1274             : 
    1275             : 
    1276             : /*
    1277             :  * MAL API
    1278             :  * The linkage between MAL interpreter and compiled C-routines
    1279             :  * is kept as simple as possible.
    1280             :  * Basically we distinguish four kinds of calling conventions:
    1281             :  * CMDcall, FCNcall, FACcall, and  PATcall.
    1282             :  * The FCNcall indicates calling a MAL procedure, which leads
    1283             :  * to a recursive call to the interpreter.
    1284             :  *
    1285             :  * CMDcall initiates calling a linked function, passing pointers
    1286             :  * to the parameters and result variable, i.e.  f(ptr a0,..., ptr aN)
    1287             :  * The function returns a MAL-SUCCEED upon success and a pointer
    1288             :  * to an exception string upon failure.
    1289             :  * Failure leads to raise-ing an exception in the interpreter loop,
    1290             :  * by either looking up the relevant exception message in the module
    1291             :  * administration or construction of a standard string.
    1292             :  *
    1293             :  * The PATcall initiates a call which contains the MAL context,
    1294             :  * i.e. f(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1295             :  * The mb provides access to the code definitions. It is primarilly
    1296             :  * used by routines intended to manipulate the code base itself, such
    1297             :  * as the optimizers. The Mal stack frame pointer provides access
    1298             :  * to the values maintained. The arguments passed are offsets
    1299             :  * into the stack frame rather than pointers to the actual value.
    1300             :  *
    1301             :  * BAT parameters require some care. Ideally, a BAT should not be kept
    1302             :  * around long. This would mean that each time we access a BAT it has to be
    1303             :  * pinned in memory and upon leaving the function, it is unpinned.
    1304             :  * This degrades performance significantly.
    1305             :  * After the parameters are fixed, we can safely free the destination
    1306             :  * variable and re-initialize it to nil.
    1307             :  *
    1308             :  */
    1309             : 
    1310             : /*
    1311             :  * The type dispatching table in getArgReference can be removed if we
    1312             :  * determine at compile time the address offset within a ValRecord.
    1313             :  * We leave this optimization for the future, it leads to about 10%
    1314             :  * improvement (100ms for 1M calls).
    1315             :  *
    1316             :  * Flow of control statements
    1317             :  * Each assignment (function call) may be part of the initialization
    1318             :  * of a barrier- block. In that case we have to test the
    1319             :  * outcome of the operation and possibly skip the block altogether.
    1320             :  * The latter is implemented as a linear scan for the corresponding
    1321             :  * labeled statemtent. This might be optimized later.
    1322             :  *
    1323             :  * You can skip to a catch block by searching for the corresponding 'lab'
    1324             :  * The return value should be set to pass the error automatically upon
    1325             :  * reaching end of function block.
    1326             :  */
    1327             : 
    1328             : /*
    1329             :  * Each time we enter a barrier block, we could keep its position in the
    1330             :  * interpreter stack frame. It forms the starting point to issue a redo.
    1331             :  * Unfortunately, this does not easily work in the presence of optimizers, which
    1332             :  * may change the order/block structure. Therefore, we simple have to search
    1333             :  * the beginning or ensure that during chkProgram the barrier/redo/leave/catch
    1334             :  * jumps are re-established.
    1335             :  *
    1336             :  * Exception handling
    1337             :  * Calling a built-in or user-defined routine may lead to an error or a
    1338             :  * cached status message to be dealt with in MAL.
    1339             :  * To improve error handling in MAL, an exception handling
    1340             :  * scheme based on @sc{catch}-@sc{exit} blocks. The @sc{catch}
    1341             :  * statement identifies a (string-valued) variable, which carries the
    1342             :  * exception message from
    1343             :  * the originally failed routine or @sc{raise} exception assignment.
    1344             :  * During normal processing @sc{catch}-@sc{exit} blocks are simply skipped.
    1345             :  * Upon receiving an exception status from a function call, we set the
    1346             :  * exception variable and skip to the first associated @sc{catch}-@sc{exit}
    1347             :  * block.
    1348             :  * MAL interpretation then continues until it reaches the end of the block.
    1349             :  * If no exception variable was defined, we should abandon the function
    1350             :  * alltogether searching for a catch block at a higher layer.
    1351             :  *
    1352             :  * For the time being we have ignored cascaded/stacked exceptions.
    1353             :  * The policy is to pass the first recognized exception to a context
    1354             :  * in which it can be handled.
    1355             :  *
    1356             :  * Exceptions raised within a linked-in function requires some care.
    1357             :  * First, the called procedure does not know anything about the MAL
    1358             :  * interpreter context. Thus, we need to return all relevant information
    1359             :  * upon leaving the linked library routine.
    1360             :  *
    1361             :  * Second, exceptional cases can be handled deeply in the recursion, where they
    1362             :  * may also be handled, i.e. by issueing an GDKerror message. The upper layers
    1363             :  * merely receive a negative integer value to indicate occurrence of an
    1364             :  * error somewhere in the calling sequence.
    1365             :  * We then have to also look into GDKerrbuf to see if there was
    1366             :  * an error raised deeply inside the system.
    1367             :  *
    1368             :  * The policy is to require all C-functions to return a string-pointer.
    1369             :  * Upon a successfull call, it is a NULL string. Otherwise it contains an
    1370             :  * encoding of the exceptional state encountered. This message
    1371             :  * starts with the exception identifer, followed by contextual details.
    1372             :  */
    1373             : 
    1374             : /*
    1375             :  * Garbage collection
    1376             :  * Garbage collection is relatively straightforward, because most values are
    1377             :  * retained on the stackframe of an interpreter call. However, two storage
    1378             :  * types and possibly user-defined type garbage collector definitions
    1379             :  * require attention: BATs and strings.
    1380             :  *
    1381             :  * A key issue is to deal with temporary BATs in an efficient way.
    1382             :  * References to bats in the buffer pool may cause dangling references
    1383             :  * at the language level. This appears as soons as your share
    1384             :  * a reference and delete the BAT from one angle. If not carefull, the
    1385             :  * dangling pointer may subsequently be associated with another BAT
    1386             :  *
    1387             :  * All string values are private to the VALrecord, which means they
    1388             :  * have to be freed explicitly before a MAL function returns.
    1389             :  * The first step is to always safe the destination variable
    1390             :  * before a function call is made.
    1391             :  */
    1392   120464015 : void garbageElement(Client cntxt, ValPtr v)
    1393             : {
    1394             :         (void) cntxt;
    1395   120464015 :         if (ATOMstorage(v->vtype) == TYPE_str) {
    1396    26249858 :                 GDKfree(v->val.sval);
    1397    26249862 :                 v->val.sval = NULL;
    1398    26249862 :                 v->len = 0;
    1399    94214157 :         } else if (v->vtype == TYPE_bat) {
    1400             :                 /*
    1401             :                  * All operations are responsible to properly set the
    1402             :                  * reference count of the BATs being produced or destroyed.
    1403             :                  * The libraries should not leave the
    1404             :                  * physical reference count being set. This is only
    1405             :                  * allowed during the execution of a GDK operation.
    1406             :                  * All references should be logical.
    1407             :                  */
    1408    26432687 :                 bat bid = v->val.bval;
    1409             :                 /* printf("garbage collecting: %d lrefs=%d refs=%d\n",
    1410             :                    bid, BBP_lrefs(bid),BBP_refs(bid));*/
    1411    26432687 :                 v->val.bval = bat_nil;
    1412    26432687 :                 if (is_bat_nil(bid))
    1413             :                         return;
    1414      190994 :                 if (!BBP_lrefs(bid))
    1415             :                         return;
    1416      190994 :                 BBPcold(bid);
    1417      190995 :                 BBPrelease(bid);
    1418    67781470 :         } else if (0 < v->vtype && v->vtype < MAXATOMS && ATOMextern(v->vtype)) {
    1419        3764 :                 GDKfree(v->val.pval);
    1420        3769 :                 v->val.pval = 0;
    1421        3769 :                 v->len = 0;
    1422             :         }
    1423             : }
    1424             : 
    1425             : /*
    1426             :  * Before we return from the interpreter, we should free all
    1427             :  * dynamically allocated objects and adjust the BAT reference counts.
    1428             :  * Early experience shows that for small stack frames the overhead
    1429             :  * is about 200 ms for a 1M function call loop (tst400e). This means that
    1430             :  * for the time being we do not introduce more complex garbage
    1431             :  * administration code.
    1432             :  *
    1433             :  * Also note that for top-level stack frames (no environment available),
    1434             :  * we should retain the value stack because it acts as a global variables.
    1435             :  * This situation is indicated by the 'global' in the stack frame.
    1436             :  * Upon termination of the session, the stack should be cleared.
    1437             :  * Beware that variables may be know polymorphic, their actual
    1438             :  * type should be saved for variables that recide on a global
    1439             :  * stack frame.
    1440             :  */
    1441      439191 : void garbageCollector(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int flag)
    1442             : {
    1443             :         int k;
    1444             :         ValPtr v;
    1445             : 
    1446      439191 :         assert(mb->vtop <= mb->vsize);
    1447      439191 :         assert(stk->stktop <= stk->stksize);
    1448             :         (void) flag;
    1449             :         (void)mb;
    1450             :         (void)cntxt;
    1451   120894041 :         for (k = 0; k < stk->stktop; k++) {
    1452             :         //      if (isVarCleanup(mb, k) ){
    1453   120454845 :                         garbageElement(cntxt, v = &stk->stk[k]);
    1454   120454850 :                         v->vtype = TYPE_int;
    1455   120454850 :                         v->val.ival = int_nil;
    1456             :         //      }
    1457             :         }
    1458      439196 : }

Generated by: LCOV version 1.14