LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_interpreter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 398 602 66.1 %
Date: 2021-10-13 02:24:04 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     1542989 : 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    41144784 :         return (ptr) &stk->stk[pci->argv[k]].val;
      40             : }
      41             : 
      42    39601795 : str malCommandCall(MalStkPtr stk, InstrPtr pci)
      43             : {
      44             :         str ret= MAL_SUCCEED;
      45             : 
      46    39601795 :         switch (pci->argc) {
      47           0 :         case 0: ret = (*pci->fcn)();
      48           0 :                 break;
      49     1010294 :         case 1: ret = (*pci->fcn)(
      50             :                         getArgReference(stk, pci, 0));
      51     1010294 :                 break;
      52      142809 :         case 2: ret = (*pci->fcn)(
      53             :                         getArgReference(stk, pci, 0),
      54             :                         getArgReference(stk, pci, 1));
      55      142801 :                 break;
      56    36342392 :         case 3: ret = (*pci->fcn)(
      57             :                         getArgReference(stk, pci, 0),
      58             :                         getArgReference(stk, pci, 1),
      59             :                         getArgReference(stk, pci, 2));
      60    36342118 :                 break;
      61      818953 :         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      818907 :                 break;
      67      732402 :         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      732313 :                 break;
      74       14450 :         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       14448 :                 break;
      82       93441 :         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       93441 :                 break;
      91      430152 :         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      430133 :                 break;
     101       16730 :         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       16731 :                 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          45 :         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          45 :                 break;
     137         111 :         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         111 :                 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     8981304 : isNotUsedIn(InstrPtr p, int start, int a)
     246             : {
     247             :         int k;
     248    20623909 :         for (k = start; k < p->argc; k++)
     249    11684500 :                 if (getArg(p, k) == a)
     250             :                         return 0;
     251             :         return 1;
     252             : }
     253             : 
     254             : MalStkPtr
     255      409400 : prepareMALstack(MalBlkPtr mb, int size)
     256             : {
     257             :         MalStkPtr stk = NULL;
     258             :         int i, res = 1;
     259             :         ValPtr lhs, rhs;
     260             : 
     261      409400 :         stk = newGlobalStack(size);
     262      409399 :         if (!stk)
     263             :                 return NULL;
     264      409399 :         stk->stktop = mb->vtop;
     265      409399 :         stk->blk = mb;
     266      409399 :         stk->workers = 0;
     267      409399 :         stk->memory = 0;
     268    81882797 :         initStack(0, res);
     269      409400 :         if(!res) {
     270           0 :                 freeStack(stk);
     271           0 :                 return NULL;
     272             :         }
     273             :         return stk;
     274             : }
     275             : 
     276      371114 : 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      371114 :         cntxt->lastcmd= time(0);
     299      371114 :         ATOMIC_SET(&cntxt->lastprint, GDKusec());
     300      371114 :         if (env != NULL) {
     301             :                 int res = 1;
     302             :                 stk = env;
     303        9320 :                 if (mb != stk->blk)
     304           0 :                         throw(MAL, "mal.interpreter","misalignment of symbols");
     305        9320 :                 if (mb->vtop > stk->stksize)
     306           0 :                         throw(MAL, "mal.interpreter","stack too small");
     307       26872 :                 initStack(env->stkbot, res);
     308        9320 :                 if(!res)
     309           0 :                         throw(MAL, "mal.interpreter", MAL_MALLOC_FAIL);
     310             :         } else {
     311      361794 :                 stk = prepareMALstack(mb, mb->vsize);
     312      361794 :                 if (stk == 0)
     313           0 :                         throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     314      361794 :                 stk->blk = mb;
     315      361794 :                 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      371114 :         if (stk->cmd && env && stk->cmd != 'f')
     334           0 :                 stk->cmd = env->cmd;
     335      371114 :         ret = runMALsequence(cntxt, mb, 1, 0, stk, env, 0);
     336             : 
     337             :         /* pass the new debug mode to the caller */
     338      371114 :         if (stk->cmd && env && stk->cmd != 'f')
     339           0 :                 env->cmd = stk->cmd;
     340      371114 :         if (!stk->keepAlive && garbageControl(getInstrPtr(mb, 0)))
     341      361794 :                 garbageCollector(cntxt, mb, stk, env != stk);
     342      371114 :         if (stk && stk != env)
     343      361794 :                 freeStack(stk);
     344      371114 :         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     1068827 : str reenterMAL(Client cntxt, MalBlkPtr mb, int startpc, int stoppc, MalStkPtr stk)
     359             : {
     360             :         str ret;
     361             :         int keepAlive;
     362             : 
     363     1068827 :         if (stk == NULL)
     364           0 :                 throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     365     1068827 :         keepAlive = stk->keepAlive;
     366     1068827 :         ret = runMALsequence(cntxt, mb, startpc, stoppc, stk, 0, 0);
     367             : 
     368             :         /* pass the new debug mode to the caller */
     369     1068827 :         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    12024054 : 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    12024054 :         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    12024389 :         runtimeProfile.ticks = runtimeProfileFunction.ticks = 0;
     467             : 
     468    12024389 :         if (stk == NULL)
     469           0 :                 throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     470             : 
     471             :         /* prepare extended backup and garbage structures */
     472    12024389 :         if (startpc+1 == stoppc) {
     473    10614319 :                 pci = getInstrPtr(mb, startpc);
     474    10614319 :                 if (pci->argc > 16) {
     475       67978 :                         backup = GDKmalloc(pci->argc * sizeof(ValRecord));
     476       67974 :                         garbage = (int*)GDKzalloc(pci->argc * sizeof(int));
     477       67967 :                         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    10546341 :                         memset(garbages, 0, sizeof(garbages));
     486             :                 }
     487     1410070 :         } else if ( mb->maxarg > 16 ){
     488      149007 :                 backup = GDKmalloc(mb->maxarg * sizeof(ValRecord));
     489      149007 :                 garbage = (int*)GDKzalloc(mb->maxarg * sizeof(int));
     490      149007 :                 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     1261063 :                 memset(garbages, 0, sizeof(garbages));
     499             :         }
     500             : 
     501             :         /* also produce event record for start of function */
     502    12024378 :         if ( startpc == 1 &&  startpc < mb->stop ){
     503             :                 startedProfileQueue = 1;
     504      410064 :                 runtimeProfileInit(cntxt, mb, stk);
     505      410064 :                 runtimeProfileBegin(cntxt, mb, stk, getInstrPtr(mb,0), &runtimeProfileFunction);
     506      410064 :                 mb->starttime = GDKusec();
     507      410064 :                 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    12024378 :         QryCtx qry_ctx = {.querytimeout=cntxt->querytimeout, .starttime=mb->starttime};
     518             : #ifndef NDEBUG
     519             :         /* very short timeout */
     520    12024378 :         QryCtx qry_ctx_abort = {.querytimeout=100, .starttime=mb->starttime};
     521             : #endif
     522             :         /* save, in case this function is called recursively */
     523    12024378 :         QryCtx *qry_ctx_save = MT_thread_get_qry_ctx();
     524    12022831 :         MT_thread_set_qry_ctx(&qry_ctx);
     525             : 
     526    70027681 :         while (stkpc < mb->stop && stkpc != stoppc) {
     527             :                 // incomplete block being executed, requires at least signature and end statement
     528    59006396 :                 MT_thread_setalgorithm(NULL);
     529    59003637 :                 pci = getInstrPtr(mb, stkpc);
     530    59003637 :                 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    59003636 :                 if (cntxt->itrace || stk->status) {
     538           0 :                         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           0 :                         if ( stk->status == 'q')
     545           0 :                                 stk->cmd = 'x';
     546             : 
     547           0 :                         if (stk->cmd == 0)
     548           0 :                                 stk->cmd = cntxt->itrace;
     549           0 :                         mdbStep(cntxt, mb, stk, stkpc);
     550           0 :                         if (stk->cmd == 'x' ) {
     551           0 :                                 stk->cmd = 0;
     552           0 :                                 stkpc = mb->stop;
     553           0 :                                 MT_thread_set_qry_ctx(&qry_ctx_abort);
     554           0 :                                 ret= createException(MAL, "mal.interpreter", "prematurely stopped client");
     555           0 :                                 break;
     556             :                         }
     557             :                 }
     558             : #endif
     559             : 
     560             :                 //Ensure we spread system resources over multiple users as well.
     561    59003636 :                 runtimeProfileBegin(cntxt, mb, stk, pci, &runtimeProfile);
     562    58998630 :                 if (runtimeProfile.ticks > lastcheck + CHECKINTERVAL) {
     563    12103572 :                         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    12116525 :                         lastcheck = runtimeProfile.ticks;
     570             :                 }
     571             : 
     572    59011583 :                 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   118764129 :                 for (i = 0; i < pci->retc; i++)
     609    59752546 :                         backup[i] = stk->stk[getArg(pci, i)];
     610             : 
     611    59011583 :                 if (garbageControl(pci)) {
     612   132963809 :                         for (i = 0; i < pci->argc; i++) {
     613   103154486 :                                 int a = getArg(pci, i);
     614             : 
     615   103154486 :                                 if (stk->stk[a].vtype == TYPE_bat && getEndScope(mb, a) == stkpc && isNotUsedIn(pci, i + 1, a))
     616     8936175 :                                         garbage[i] = a;
     617             :                                 else
     618    94218500 :                                         garbage[i] = -1;
     619             :                         }
     620             :                 }
     621             : 
     622    59011772 :                 freeException(ret);
     623             :                 ret = MAL_SUCCEED;
     624    59009584 :                 switch (pci->token) {
     625     3506076 :                 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     5970556 :                         for (k = 0, i = pci->retc; k < pci->retc && i < pci->argc; i++, k++) {
     642     2464480 :                                 lhs = &stk->stk[pci->argv[k]];
     643     2464480 :                                 rhs = &stk->stk[pci->argv[i]];
     644     2464480 :                                 if(VALcopy(lhs, rhs) == NULL) {
     645           0 :                                         ret = createException(MAL, "mal.interpreter", MAL_MALLOC_FAIL);
     646           0 :                                         break;
     647     2464480 :                                 } else if (lhs->vtype == TYPE_bat && !is_bat_nil(lhs->val.bval))
     648        4066 :                                         BBPretain(lhs->val.bval);
     649             :                         }
     650             :                         break;
     651    14487809 :                 case PATcall:
     652    14487809 :                         if (pci->fcn == NULL) {
     653           0 :                                 ret = createException(MAL,"mal.interpreter", "address of pattern %s.%s missing", pci->modname, pci->fcnname);
     654             :                         } else {
     655    14487809 :                                 TRC_DEBUG(ALGO, "calling %s.%s\n", pci->modname ? pci->modname : "<null>", pci->fcnname ? pci->fcnname : "<null>");
     656    14487809 :                                 ret = (*pci->fcn)(cntxt, mb, stk, pci);
     657             : #ifndef NDEBUG
     658    14485713 :                                 if (ret == MAL_SUCCEED) {
     659             :                                         /* check that the types of actual results match
     660             :                                          * expected results */
     661    29659664 :                                         for (i = 0; i < pci->retc; i++) {
     662    15176202 :                                                 int a = getArg(pci, i);
     663    15176202 :                                                 int t = getArgType(mb, pci, i);
     664             : 
     665    15176202 :                                                 if (isaBatType(t)) {
     666     4802375 :                                                         bat bid = stk->stk[a].val.bval;
     667     4802375 :                                                         BAT *_b = BATdescriptor(bid);
     668     4803195 :                                                         t = getBatType(t);
     669     4803195 :                                                         assert(stk->stk[a].vtype == TYPE_bat);
     670    13997313 :                                                         assert(is_bat_nil(bid) ||
     671             :                                                                    t == TYPE_any ||
     672             :                                                                    ATOMtype(_b->ttype) == ATOMtype(t));
     673     4803195 :                                                         if(_b) BBPunfix(bid);
     674             :                                                 } else {
     675    10373827 :                                                         assert(t == stk->stk[a].vtype);
     676             :                                                 }
     677             :                                         }
     678             :                                 }
     679             : #endif
     680             :                         }
     681             :                         break;
     682    39601265 :                 case CMDcall:
     683    39601265 :                         TRC_DEBUG(ALGO, "calling %s.%s\n", pci->modname ? pci->modname : "<null>", pci->fcnname ? pci->fcnname : "<null>");
     684    39601265 :                         ret = malCommandCall(stk, pci);
     685             : #ifndef NDEBUG
     686    39600716 :                         if (ret == MAL_SUCCEED) {
     687             :                                 /* check that the types of actual results match
     688             :                                  * expected results */
     689    79623366 :                                 for (i = 0; i < pci->retc; i++) {
     690    40024231 :                                         int a = getArg(pci, i);
     691    40024231 :                                         int t = getArgType(mb, pci, i);
     692             : 
     693    40024231 :                                         if (isaBatType(t)) {
     694             :                                                 //bat bid = stk->stk[a].val.bval;
     695    22546770 :                                                 t = getBatType(t);
     696    22546770 :                                                 assert(stk->stk[a].vtype == TYPE_bat);
     697             :                                                 //assert( !is_bat_nil(bid));
     698    22546770 :                                                 assert(t != TYPE_any);
     699             :                                                 //assert( ATOMtype(BBP_desc(bid)->ttype) == ATOMtype(t));
     700             :                                         } else {
     701    17477461 :                                                 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       38906 :                 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       38906 :                                 stk->pcup = stkpc;
     744       38906 :                                 nstk = prepareMALstack(pci->blk, pci->blk->vsize);
     745       38906 :                                 if (nstk == 0){
     746           0 :                                         ret= createException(MAL,"mal.interpreter",MAL_STACK_FAIL);
     747           0 :                                         break;
     748             :                                 }
     749             : 
     750             :                                 /*safeguardStack*/
     751       38906 :                                 nstk->stkdepth = nstk->stksize + stk->stkdepth;
     752       38906 :                                 nstk->calldepth = stk->calldepth + 1;
     753       38906 :                                 nstk->up = stk;
     754       38906 :                                 if (nstk->calldepth > 256) {
     755           1 :                                         ret= createException(MAL, "mal.interpreter", MAL_CALLDEPTH_FAIL);
     756           1 :                                         GDKfree(nstk);
     757           1 :                                         break;
     758             :                                 }
     759       38905 :                                 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       38905 :                                 q= getInstrPtr(pci->blk,0);
     768       38905 :                                 arg = q->retc;
     769      134900 :                                 for (ii = pci->retc; ii < pci->argc; ii++,arg++) {
     770       95995 :                                         lhs = &nstk->stk[q->argv[arg]];
     771       95995 :                                         rhs = &stk->stk[pci->argv[ii]];
     772       95995 :                                         if(VALcopy(lhs, rhs) == NULL) {
     773           0 :                                                 GDKfree(nstk);
     774           0 :                                                 ret = createException(MAL, "mal.interpreter", MAL_MALLOC_FAIL);
     775           0 :                                                 break;
     776       95995 :                                         } else if (lhs->vtype == TYPE_bat)
     777         159 :                                                 BBPretain(lhs->val.bval);
     778             :                                 }
     779       38905 :                                 if (ret == MAL_SUCCEED && ii == pci->argc) {
     780       38905 :                                         ret = runMALsequence(cntxt, pci->blk, 1, pci->blk->stop, nstk, stk, pci);
     781       38905 :                                         garbageCollector(cntxt, pci->blk, nstk, 0);
     782       38905 :                                         arg = q->retc;
     783      134900 :                                         for (ii = pci->retc; ii < pci->argc; ii++,arg++) {
     784       95995 :                                                 lhs = &nstk->stk[q->argv[arg]];
     785       95995 :                                                 if (lhs->vtype == TYPE_bat)
     786           0 :                                                         BBPrelease(lhs->val.bval);
     787             :                                         }
     788       38905 :                                         GDKfree(nstk);
     789             :                                 }
     790             :                         }
     791             :                         break;
     792             :                 case NOOPsymbol:
     793             :                 case REMsymbol:
     794             :                         break;
     795      375388 :                 case ENDsymbol:
     796      375388 :                         if (getInstrPtr(mb, 0)->token == FACTORYsymbol)
     797           0 :                                 ret = shutdownFactory(cntxt, mb);
     798      375388 :                         runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
     799      375388 :                         runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb,0), &runtimeProfileFunction);
     800      375388 :                         if (pcicaller && garbageControl(getInstrPtr(mb, 0)))
     801        5942 :                                 garbageCollector(cntxt, mb, stk, TRUE);
     802      375388 :                         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      375388 :                         stkpc = mb->stop;    // force end of loop
     808      375388 :                         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    58631355 :                 if( mb->stop <= 1)
     838           0 :                         continue;
     839    58631355 :                 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    58633015 :                 if ( pci->token != FACcall && ret== MAL_SUCCEED) {
     844   116379970 :                         for (i = 0; i < pci->retc; i++) {
     845    58753734 :                                 lhs = &backup[i];
     846    86113169 :                                 if (BATatoms[lhs->vtype].atomUnfix &&
     847    27359604 :                                         (*BATatoms[lhs->vtype].atomUnfix)(VALget(lhs)) != GDK_SUCCEED) {
     848           0 :                                         if (ret == MAL_SUCCEED)
     849           0 :                                                 ret = createException(MAL, "mal.propertyCheck", GDK_EXCEPTION);
     850             :                                 }
     851    58753565 :                                 if (ATOMextern(lhs->vtype) &&
     852      943575 :                                         lhs->val.pval &&
     853      102902 :                                         lhs->val.pval != ATOMnilptr(lhs->vtype) &&
     854      102902 :                                         lhs->val.pval != stk->stk[getArg(pci, i)].val.pval)
     855      101124 :                                         GDKfree(lhs->val.pval);
     856             :                         }
     857    57626236 :                         if (GDKdebug & (CHECKMASK|PROPMASK) && exceptionVar < 0) {
     858             :                                 BAT *b;
     859             : 
     860   115970886 :                                 for (i = 0; i < pci->retc; i++) {
     861    58541246 :                                         if (garbage[i] == -1 && stk->stk[getArg(pci, i)].vtype == TYPE_bat &&
     862    26909959 :                                                 !is_bat_nil(stk->stk[getArg(pci, i)].val.bval)) {
     863    26895806 :                                                 assert(stk->stk[getArg(pci, i)].val.bval > 0);
     864    26895806 :                                                 b = BBPquickdesc(stk->stk[getArg(pci, i)].val.bval);
     865    26891519 :                                                 if (b == NULL) {
     866           0 :                                                         if (ret == MAL_SUCCEED)
     867           0 :                                                                 ret = createException(MAL, "mal.propertyCheck", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     868           0 :                                                         continue;
     869             :                                                 }
     870    26891519 :                                                 b = BATdescriptor(stk->stk[getArg(pci, i)].val.bval);
     871    26895383 :                                                 if (b) {
     872    26895279 :                                                         BATassertProps(b);
     873    26896346 :                                                         BBPunfix(b->batCacheid);
     874             :                                                 }
     875             :                                         }
     876             :                                 }
     877             :                         }
     878             : 
     879             :                         /* general garbage collection */
     880    57627632 :                         if (ret == MAL_SUCCEED && garbageControl(pci)) {
     881   133021301 :                                 for (i = 0; i < pci->argc; i++) {
     882   103215019 :                                         int a = getArg(pci, i);
     883             : 
     884   103215019 :                                         if (isaBatType(getArgType(mb, pci, i))) {
     885             :                                                 bat bid = stk->stk[a].val.bval;
     886             : 
     887    62051349 :                                                 if (garbage[i] >= 0) {
     888     8892336 :                                                         bid = stk->stk[garbage[i]].val.bval;
     889     8892336 :                                                         stk->stk[garbage[i]].val.bval = bat_nil;
     890     8892336 :                                                         BBPcold(bid);
     891     8889786 :                                                         BBPrelease(bid);
     892             :                                                 }
     893             :                                         }
     894             :                                 }
     895             :                         }
     896             :                 }
     897             : 
     898             :                 /* Exception handling */
     899    58632804 :                 if (localGDKerrbuf && localGDKerrbuf[0]) {
     900           2 :                         if( ret == MAL_SUCCEED)
     901           2 :                                 ret = createException(MAL,"mal.interpreter",GDK_EXCEPTION);
     902             :                         // TODO take properly care of the GDK exception
     903           2 :                         localGDKerrbuf[0]=0;
     904             :                 }
     905             : 
     906    58632804 :                 if (ret != MAL_SUCCEED) {
     907             :                         str msg = 0;
     908             : 
     909             : #ifndef NDEBUG
     910        3039 :                         if (stk->cmd) {
     911           0 :                                 mnstr_printf(cntxt->fdout, "!ERROR: %s\n", ret);
     912           0 :                                 stk->cmd = '\n'; /* in debugging go to step mode */
     913           0 :                                 mdbStep(cntxt, mb, stk, stkpc);
     914           0 :                                 if (stk->cmd == 'x' || stk->cmd == 'q' ) {
     915           0 :                                         stkpc = mb->stop;
     916           0 :                                         continue;
     917             :                                 }
     918           0 :                                 if (stk->cmd == 'r') {
     919           0 :                                         stk->cmd = 'n';
     920             :                                         stkpc = startpc;
     921             :                                         exceptionVar = -1;
     922           0 :                                         continue;
     923             :                                 }
     924             :                         }
     925             : #endif
     926             :                         /* Detect any exception received from the implementation. */
     927             :                         /* The first identifier is an optional exception name */
     928        3039 :                         if (strstr(ret, "!skip-to-end")) {
     929           0 :                                 freeException(ret);
     930             :                                 ret = MAL_SUCCEED;
     931           0 :                                 stkpc = mb->stop;
     932           0 :                                 continue;
     933             :                         }
     934             :                         /*
     935             :                          * Exceptions are caught based on their name, which is part of the
     936             :                          * exception message. The ANYexception variable catches all.
     937             :                          */
     938             :                         exceptionVar = -1;
     939        3039 :                         msg = strchr(ret, ':');
     940        3039 :                         if (msg) {
     941        3039 :                                 exceptionVar = findVariableLength(mb, ret, (int)(msg - ret));
     942             :                         }
     943        3039 :                         if (exceptionVar == -1)
     944        3024 :                                 exceptionVar = findVariable(mb, "ANYexception");
     945             : 
     946             :                         /* unknown exceptions lead to propagation */
     947        3038 :                         if (exceptionVar == -1) {
     948        3023 :                                 if (cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout) {
     949           5 :                                         freeException(ret);
     950           5 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     951             :                                 }
     952        3023 :                                 stkpc = mb->stop;
     953        3023 :                                 continue;
     954             :                         }
     955             :                         /* assure correct variable type */
     956          15 :                         if (getVarType(mb, exceptionVar) == TYPE_str) {
     957             :                                 /* watch out for concurrent access */
     958          15 :                                 MT_lock_set(&mal_contextLock);
     959          15 :                                 v = &stk->stk[exceptionVar];
     960          15 :                                 if (v->val.sval)
     961           3 :                                         freeException(v->val.sval);    /* old exception*/
     962          15 :                                 VALset(v, TYPE_str, ret);
     963             :                                 ret = MAL_SUCCEED;
     964          15 :                                 MT_lock_unset(&mal_contextLock);
     965             :                         } else {
     966           0 :                                 mnstr_printf(cntxt->fdout, "%s", ret);
     967           0 :                                 freeException(ret);
     968             :                                 ret = MAL_SUCCEED;
     969             :                         }
     970             :                         /* position yourself at the catch instruction for further decisions */
     971             :                         /* skipToCatch(exceptionVar,@2,@3) */
     972             : #ifndef NDEBUG
     973          15 :                         if (stk->cmd == 'C') {
     974           0 :                                 stk->cmd = 'n';
     975           0 :                                 mdbStep(cntxt, mb, stk, stkpc);
     976           0 :                                 if (stk->cmd == 'x' ) {
     977           0 :                                         stkpc = mb->stop;
     978           0 :                                         continue;
     979             :                                 }
     980             :                         }
     981             : #endif
     982             :                         /* skip to catch block or end */
     983         135 :                         for (; stkpc < mb->stop; stkpc++) {
     984         135 :                                 InstrPtr l = getInstrPtr(mb, stkpc);
     985         135 :                                 if (l->barrier == CATCHsymbol) {
     986             :                                         int j;
     987          29 :                                         for (j = 0; j < l->retc; j++)
     988          22 :                                                 if (getArg(l, j) == exceptionVar)
     989             :                                                         break;
     990           7 :                                                 else if (strcmp(getArgName(mb, l, j), "ANYexception") == 0)
     991             :                                                         break;
     992          22 :                                         if (j < l->retc)
     993             :                                                 break;
     994             :                                 }
     995             :                         }
     996          15 :                         if (stkpc == mb->stop) {
     997           0 :                                 if (cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout){
     998           0 :                                         freeException(ret);
     999           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
    1000           0 :                                         stkpc = mb->stop;
    1001             :                                 }
    1002           0 :                                 continue;
    1003             :                         }
    1004          15 :                         pci = getInstrPtr(mb, stkpc);
    1005             :                 }
    1006             : 
    1007             :                 /*
    1008             :                  * After the expression has been evaluated we should check for
    1009             :                  * a possible change in the control flow.
    1010             :                  */
    1011    58629780 :                 switch (pci->barrier) {
    1012      706505 :                 case BARRIERsymbol:
    1013      706505 :                         v = &stk->stk[getDestVar(pci)];
    1014             :                         /* skip to end of barrier, depends on the type */
    1015      706505 :                         switch (v->vtype) {
    1016      705986 :                         case TYPE_bit:
    1017      705986 :                                 if (v->val.btval == FALSE || is_bit_nil(v->val.btval))
    1018      661878 :                                         stkpc = pci->jump;
    1019             :                                 break;
    1020           0 :                         case TYPE_bte:
    1021           0 :                                 if (is_bte_nil(v->val.btval))
    1022           0 :                                         stkpc = pci->jump;
    1023             :                                 break;
    1024         486 :                         case TYPE_oid:
    1025         486 :                                 if (is_oid_nil(v->val.oval))
    1026         371 :                                         stkpc = pci->jump;
    1027             :                                 break;
    1028           0 :                         case TYPE_sht:
    1029           0 :                                 if (is_sht_nil(v->val.shval))
    1030           0 :                                         stkpc = pci->jump;
    1031             :                                 break;
    1032          11 :                         case TYPE_int:
    1033          11 :                                 if (is_int_nil(v->val.ival))
    1034           0 :                                         stkpc = pci->jump;
    1035             :                                 break;
    1036          15 :                         case TYPE_lng:
    1037          15 :                                 if (is_lng_nil(v->val.lval))
    1038           0 :                                         stkpc = pci->jump;
    1039             :                                 break;
    1040             : #ifdef HAVE_HGE
    1041           0 :                         case TYPE_hge:
    1042           0 :                                 if (is_hge_nil(v->val.hval))
    1043           0 :                                         stkpc = pci->jump;
    1044             :                                 break;
    1045             : #endif
    1046           1 :                         case TYPE_flt:
    1047           1 :                                 if (is_flt_nil(v->val.fval))
    1048           0 :                                         stkpc = pci->jump;
    1049             :                                 break;
    1050           0 :                         case TYPE_dbl:
    1051           0 :                                 if (is_dbl_nil(v->val.dval))
    1052           0 :                                         stkpc = pci->jump;
    1053             :                                 break;
    1054           0 :                         case TYPE_str:
    1055           0 :                                 if (strNil(v->val.sval))
    1056           0 :                                         stkpc = pci->jump;
    1057             :                                 break;
    1058           6 :                         default:
    1059           6 :                                 ret = createException(MAL,"mal.interpreter", "%s: Unknown barrier type", getVarName(mb, getDestVar(pci)));
    1060             :                         }
    1061      706505 :                         stkpc++;
    1062      706505 :                         break;
    1063    17229283 :                 case LEAVEsymbol:
    1064             :                 case REDOsymbol:
    1065    17229283 :                         v = &stk->stk[getDestVar(pci)];
    1066             :                         /* skip to end of barrier, depending on the type */
    1067    17229283 :                         switch (v->vtype) {
    1068     1000850 :                         case TYPE_bit:
    1069     1000850 :                                 if (v->val.btval == TRUE )
    1070     1000440 :                                         stkpc = pci->jump;
    1071             :                                 else
    1072         410 :                                         stkpc++;
    1073             :                                 break;
    1074           0 :                         case TYPE_str:
    1075           0 :                                 if (!strNil(v->val.sval))
    1076           0 :                                         stkpc = pci->jump;
    1077             :                                 else
    1078           0 :                                         stkpc++;
    1079             :                                 break;
    1080       25936 :                         case TYPE_oid:
    1081       25936 :                                 if (!is_oid_nil(v->val.oval))
    1082       25826 :                                         stkpc = pci->jump;
    1083             :                                 else
    1084         110 :                                         stkpc++;
    1085             :                                 break;
    1086           0 :                         case TYPE_sht:
    1087           0 :                                 if (!is_sht_nil(v->val.shval))
    1088           0 :                                         stkpc = pci->jump;
    1089             :                                 else
    1090           0 :                                         stkpc++;
    1091             :                                 break;
    1092     1992242 :                         case TYPE_int:
    1093     1992242 :                                 if (!is_int_nil(v->val.ival))
    1094     1992236 :                                         stkpc = pci->jump;
    1095             :                                 else
    1096           6 :                                         stkpc++;
    1097             :                                 break;
    1098           0 :                         case TYPE_bte:
    1099           0 :                                 if (!is_bte_nil(v->val.btval))
    1100           0 :                                         stkpc = pci->jump;
    1101             :                                 else
    1102           0 :                                         stkpc++;
    1103             :                                 break;
    1104    14210253 :                         case TYPE_lng:
    1105    14210253 :                                 if (!is_lng_nil(v->val.lval))
    1106    14210238 :                                         stkpc = pci->jump;
    1107             :                                 else
    1108          15 :                                         stkpc++;
    1109             :                                 break;
    1110             : #ifdef HAVE_HGE
    1111           0 :                         case TYPE_hge:
    1112           0 :                                 if (!is_hge_nil(v->val.hval))
    1113           0 :                                         stkpc = pci->jump;
    1114             :                                 else
    1115           0 :                                         stkpc++;
    1116             :                                 break;
    1117             : #endif
    1118           2 :                         case TYPE_flt:
    1119           2 :                                 if (!is_flt_nil(v->val.fval))
    1120           1 :                                         stkpc = pci->jump;
    1121             :                                 else
    1122           1 :                                         stkpc++;
    1123             :                                 break;
    1124           0 :                         case TYPE_dbl:
    1125           0 :                                 if (!is_dbl_nil(v->val.dval))
    1126           0 :                                         stkpc = pci->jump;
    1127             :                                 else
    1128           0 :                                         stkpc++;
    1129             :                                 break;
    1130             :                         default:
    1131             :                                 break;
    1132             :                         }
    1133             :                         break;
    1134          33 :                 case CATCHsymbol:
    1135             :                         /* catch blocks are skipped unless
    1136             :                            searched for explicitly*/
    1137          33 :                         if (exceptionVar < 0) {
    1138          15 :                                 stkpc = pci->jump;
    1139          15 :                                 break;
    1140             :                         }
    1141             :                         exceptionVar = -1;
    1142          18 :                         stkpc++;
    1143          18 :                         break;
    1144       44144 :                 case EXITsymbol:
    1145       44144 :                         if (getDestVar(pci) == exceptionVar)
    1146             :                                 exceptionVar = -1;
    1147       44144 :                         stkpc++;
    1148       44144 :                         break;
    1149           6 :                 case RAISEsymbol:
    1150           6 :                         exceptionVar = getDestVar(pci);
    1151             :                         //freeException(ret);
    1152             :                         ret = MAL_SUCCEED;
    1153           6 :                         if (getVarType(mb, getDestVar(pci)) == TYPE_str) {
    1154             :                                 char nme[256];
    1155           4 :                                 snprintf(nme,256,"%s.%s[%d]", getModuleId(getInstrPtr(mb,0)), getFunctionId(getInstrPtr(mb,0)), stkpc);
    1156           4 :                                 ret = createException(MAL, nme, "%s", stk->stk[getDestVar(pci)].val.sval);
    1157             :                         }
    1158             :                         /* skipToCatch(exceptionVar, @2, stk) */
    1159             : #ifndef NDEBUG
    1160           6 :                         if (stk->cmd == 'C') {
    1161           0 :                                 stk->cmd = 'n';
    1162           0 :                                 mdbStep(cntxt, mb, stk, stkpc);
    1163           0 :                                 if (stk->cmd == 'x' ) {
    1164           0 :                                         stkpc = mb->stop;
    1165           0 :                                         continue;
    1166             :                                 }
    1167             :                         }
    1168             : #endif
    1169             :                         /* skip to catch block or end */
    1170          22 :                         for (; stkpc < mb->stop; stkpc++) {
    1171          19 :                                 InstrPtr l = getInstrPtr(mb, stkpc);
    1172          19 :                                 if (l->barrier == CATCHsymbol) {
    1173             :                                         int j;
    1174           3 :                                         for (j = 0; j < l->retc; j++)
    1175           3 :                                                 if (getArg(l, j) == exceptionVar)
    1176             :                                                         break;
    1177           0 :                                                 else if (strcmp(getArgName(mb, l, j), "ANYexception") == 0)
    1178             :                                                         break;
    1179           3 :                                         if (j < l->retc)
    1180             :                                                 break;
    1181             :                                 }
    1182             :                         }
    1183           6 :                         if (stkpc == mb->stop) {
    1184           3 :                                 runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
    1185           3 :                                 runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb,0), &runtimeProfileFunction);
    1186           3 :                                 break;
    1187             :                         }
    1188             :                         if (stkpc == mb->stop)
    1189             :                                 ret = mb->errors = createMalException(mb, stkpc, TYPE,
    1190             :                                         "Exception raised\n");
    1191             :                         break;
    1192     1000022 :                 case YIELDsymbol:     /* to be defined */
    1193     1000022 :                         if( startedProfileQueue)
    1194          12 :                                 runtimeProfileFinish(cntxt, mb, stk);
    1195     1000022 :                         if ( backup != backups) GDKfree(backup);
    1196     1000022 :                         if ( garbage != garbages) GDKfree(garbage);
    1197     1000022 :                         ret = yieldFactory(mb, pci, stkpc);
    1198     1000022 :                         MT_thread_set_qry_ctx(qry_ctx_save);
    1199     1000022 :                         return ret;
    1200       32606 :                 case RETURNsymbol:
    1201             :                         /* Return from factory involves cleanup */
    1202             : 
    1203       32606 :                         if (getInstrPtr(mb, 0)->token == FACTORYsymbol) {
    1204           3 :                                 yieldResult(mb, pci, stkpc);
    1205           3 :                                 shutdownFactory(cntxt, mb);
    1206             :                         } else {
    1207             :                                 /* a fake multi-assignment */
    1208       32603 :                                 if (env != NULL && pcicaller != NULL) {
    1209             :                                         InstrPtr pp = pci;
    1210             :                                         pci = pcicaller;
    1211       67779 :                                         for (i = 0; i < pci->retc; i++) {
    1212       35178 :                                                 rhs = &stk->stk[pp->argv[i]];
    1213       35178 :                                                 lhs = &env->stk[pci->argv[i]];
    1214       35178 :                                                 if(VALcopy(lhs, rhs) == NULL) {
    1215           0 :                                                         ret = createException(MAL, "mal.interpreter", MAL_MALLOC_FAIL);
    1216           0 :                                                         break;
    1217       35178 :                                                 } else if (lhs->vtype == TYPE_bat)
    1218        3187 :                                                         BBPretain(lhs->val.bval);
    1219             :                                         }
    1220       32601 :                                         if (garbageControl(getInstrPtr(mb, 0)))
    1221       32562 :                                                 garbageCollector(cntxt, mb, stk, TRUE);
    1222             :                                         /* reset the clock */
    1223       32601 :                                         runtimeProfileExit(cntxt, mb, stk, pp, &runtimeProfile);
    1224       32601 :                                         runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb,0), &runtimeProfileFunction);
    1225             :                                 }
    1226             :                         }
    1227       32606 :                         stkpc = mb->stop;
    1228       32606 :                         continue;
    1229    39617181 :                 default:
    1230    39617181 :                         stkpc++;
    1231             :                 }
    1232    57597152 :                 if (cntxt->querytimeout && mb->starttime && GDKusec()- mb->starttime > cntxt->querytimeout){
    1233           1 :                         if (ret == MAL_SUCCEED)
    1234           1 :                                 ret= createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
    1235           1 :                         stkpc= mb->stop;
    1236             :                 }
    1237             :         }
    1238    11021286 :         MT_thread_set_qry_ctx(qry_ctx_save);
    1239             : 
    1240             :         /* if we could not find the exception variable, cascade a new one */
    1241    11019501 :         if (exceptionVar >= 0) {
    1242             :                 char nme[256];
    1243           3 :                 snprintf(nme,256,"%s.%s[%d]", getModuleId(getInstrPtr(mb,0)), getFunctionId(getInstrPtr(mb,0)), stkpc);
    1244           3 :                 if (ret != MAL_SUCCEED) {
    1245             :                         str new, n;
    1246           2 :                         n = createException(MAL,nme,"exception not caught");
    1247             :                         if (n) {
    1248           2 :                                 new = GDKzalloc(strlen(ret) + strlen(n) +16);
    1249           2 :                                 if (new){
    1250           2 :                                         strcpy(new, ret);
    1251           2 :                                         if( new[strlen(new)-1] != '\n')
    1252           1 :                                                 strcat(new,"\n");
    1253           2 :                                         strcat(new,"!");
    1254           2 :                                         strcat(new,n);
    1255           2 :                                         freeException(n);
    1256           2 :                                         freeException(ret);
    1257             :                                         ret = new;
    1258             :                                 } else {
    1259           0 :                                         freeException(ret);
    1260             :                                         ret = n;
    1261             :                                 }
    1262             :                         }
    1263             :                 } else {
    1264           1 :                         ret = createException(MAL, nme, "Exception not caught");
    1265             :                 }
    1266             :         }
    1267    11019501 :         if( startedProfileQueue)
    1268      410052 :                 runtimeProfileFinish(cntxt, mb, stk);
    1269    11019501 :         if ( backup != backups) GDKfree(backup);
    1270    11019628 :         if ( garbage != garbages) GDKfree(garbage);
    1271             :         return ret;
    1272             : }
    1273             : 
    1274             : 
    1275             : /*
    1276             :  * MAL API
    1277             :  * The linkage between MAL interpreter and compiled C-routines
    1278             :  * is kept as simple as possible.
    1279             :  * Basically we distinguish four kinds of calling conventions:
    1280             :  * CMDcall, FCNcall, FACcall, and  PATcall.
    1281             :  * The FCNcall indicates calling a MAL procedure, which leads
    1282             :  * to a recursive call to the interpreter.
    1283             :  *
    1284             :  * CMDcall initiates calling a linked function, passing pointers
    1285             :  * to the parameters and result variable, i.e.  f(ptr a0,..., ptr aN)
    1286             :  * The function returns a MAL-SUCCEED upon success and a pointer
    1287             :  * to an exception string upon failure.
    1288             :  * Failure leads to raise-ing an exception in the interpreter loop,
    1289             :  * by either looking up the relevant exception message in the module
    1290             :  * administration or construction of a standard string.
    1291             :  *
    1292             :  * The PATcall initiates a call which contains the MAL context,
    1293             :  * i.e. f(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1294             :  * The mb provides access to the code definitions. It is primarilly
    1295             :  * used by routines intended to manipulate the code base itself, such
    1296             :  * as the optimizers. The Mal stack frame pointer provides access
    1297             :  * to the values maintained. The arguments passed are offsets
    1298             :  * into the stack frame rather than pointers to the actual value.
    1299             :  *
    1300             :  * BAT parameters require some care. Ideally, a BAT should not be kept
    1301             :  * around long. This would mean that each time we access a BAT it has to be
    1302             :  * pinned in memory and upon leaving the function, it is unpinned.
    1303             :  * This degrades performance significantly.
    1304             :  * After the parameters are fixed, we can safely free the destination
    1305             :  * variable and re-initialize it to nil.
    1306             :  *
    1307             :  */
    1308             : 
    1309             : /*
    1310             :  * The type dispatching table in getArgReference can be removed if we
    1311             :  * determine at compile time the address offset within a ValRecord.
    1312             :  * We leave this optimization for the future, it leads to about 10%
    1313             :  * improvement (100ms for 1M calls).
    1314             :  *
    1315             :  * Flow of control statements
    1316             :  * Each assignment (function call) may be part of the initialization
    1317             :  * of a barrier- block. In that case we have to test the
    1318             :  * outcome of the operation and possibly skip the block altogether.
    1319             :  * The latter is implemented as a linear scan for the corresponding
    1320             :  * labeled statemtent. This might be optimized later.
    1321             :  *
    1322             :  * You can skip to a catch block by searching for the corresponding 'lab'
    1323             :  * The return value should be set to pass the error automatically upon
    1324             :  * reaching end of function block.
    1325             :  */
    1326             : 
    1327             : /*
    1328             :  * Each time we enter a barrier block, we could keep its position in the
    1329             :  * interpreter stack frame. It forms the starting point to issue a redo.
    1330             :  * Unfortunately, this does not easily work in the presence of optimizers, which
    1331             :  * may change the order/block structure. Therefore, we simple have to search
    1332             :  * the beginning or ensure that during chkProgram the barrier/redo/leave/catch
    1333             :  * jumps are re-established.
    1334             :  *
    1335             :  * Exception handling
    1336             :  * Calling a built-in or user-defined routine may lead to an error or a
    1337             :  * cached status message to be dealt with in MAL.
    1338             :  * To improve error handling in MAL, an exception handling
    1339             :  * scheme based on @sc{catch}-@sc{exit} blocks. The @sc{catch}
    1340             :  * statement identifies a (string-valued) variable, which carries the
    1341             :  * exception message from
    1342             :  * the originally failed routine or @sc{raise} exception assignment.
    1343             :  * During normal processing @sc{catch}-@sc{exit} blocks are simply skipped.
    1344             :  * Upon receiving an exception status from a function call, we set the
    1345             :  * exception variable and skip to the first associated @sc{catch}-@sc{exit}
    1346             :  * block.
    1347             :  * MAL interpretation then continues until it reaches the end of the block.
    1348             :  * If no exception variable was defined, we should abandon the function
    1349             :  * alltogether searching for a catch block at a higher layer.
    1350             :  *
    1351             :  * For the time being we have ignored cascaded/stacked exceptions.
    1352             :  * The policy is to pass the first recognized exception to a context
    1353             :  * in which it can be handled.
    1354             :  *
    1355             :  * Exceptions raised within a linked-in function requires some care.
    1356             :  * First, the called procedure does not know anything about the MAL
    1357             :  * interpreter context. Thus, we need to return all relevant information
    1358             :  * upon leaving the linked library routine.
    1359             :  *
    1360             :  * Second, exceptional cases can be handled deeply in the recursion, where they
    1361             :  * may also be handled, i.e. by issueing an GDKerror message. The upper layers
    1362             :  * merely receive a negative integer value to indicate occurrence of an
    1363             :  * error somewhere in the calling sequence.
    1364             :  * We then have to also look into GDKerrbuf to see if there was
    1365             :  * an error raised deeply inside the system.
    1366             :  *
    1367             :  * The policy is to require all C-functions to return a string-pointer.
    1368             :  * Upon a successfull call, it is a NULL string. Otherwise it contains an
    1369             :  * encoding of the exceptional state encountered. This message
    1370             :  * starts with the exception identifer, followed by contextual details.
    1371             :  */
    1372             : 
    1373             : /*
    1374             :  * Garbage collection
    1375             :  * Garbage collection is relatively straightforward, because most values are
    1376             :  * retained on the stackframe of an interpreter call. However, two storage
    1377             :  * types and possibly user-defined type garbage collector definitions
    1378             :  * require attention: BATs and strings.
    1379             :  *
    1380             :  * A key issue is to deal with temporary BATs in an efficient way.
    1381             :  * References to bats in the buffer pool may cause dangling references
    1382             :  * at the language level. This appears as soons as your share
    1383             :  * a reference and delete the BAT from one angle. If not carefull, the
    1384             :  * dangling pointer may subsequently be associated with another BAT
    1385             :  *
    1386             :  * All string values are private to the VALrecord, which means they
    1387             :  * have to be freed explicitly before a MAL function returns.
    1388             :  * The first step is to always safe the destination variable
    1389             :  * before a function call is made.
    1390             :  */
    1391   110368363 : void garbageElement(Client cntxt, ValPtr v)
    1392             : {
    1393             :         (void) cntxt;
    1394   110368363 :         if (ATOMstorage(v->vtype) == TYPE_str) {
    1395    26436085 :                 GDKfree(v->val.sval);
    1396    26436085 :                 v->val.sval = NULL;
    1397    26436085 :                 v->len = 0;
    1398    83932278 :         } else if (v->vtype == TYPE_bat) {
    1399             :                 /*
    1400             :                  * All operations are responsible to properly set the
    1401             :                  * reference count of the BATs being produced or destroyed.
    1402             :                  * The libraries should not leave the
    1403             :                  * physical reference count being set. This is only
    1404             :                  * allowed during the execution of a GDK operation.
    1405             :                  * All references should be logical.
    1406             :                  */
    1407    17688566 :                 bat bid = v->val.bval;
    1408             :                 /* printf("garbage collecting: %d lrefs=%d refs=%d\n",
    1409             :                    bid, BBP_lrefs(bid),BBP_refs(bid));*/
    1410    17688566 :                 v->val.bval = bat_nil;
    1411    17688566 :                 if (is_bat_nil(bid))
    1412             :                         return;
    1413      169551 :                 if (!BBP_lrefs(bid))
    1414             :                         return;
    1415      169551 :                 BBPcold(bid);
    1416      169550 :                 BBPrelease(bid);
    1417    66243712 :         } else if (0 < v->vtype && v->vtype < MAXATOMS && ATOMextern(v->vtype)) {
    1418        4172 :                 GDKfree(v->val.pval);
    1419        4172 :                 v->val.pval = 0;
    1420        4172 :                 v->len = 0;
    1421             :         }
    1422             : }
    1423             : 
    1424             : /*
    1425             :  * Before we return from the interpreter, we should free all
    1426             :  * dynamically allocated objects and adjust the BAT reference counts.
    1427             :  * Early experience shows that for small stack frames the overhead
    1428             :  * is about 200 ms for a 1M function call loop (tst400e). This means that
    1429             :  * for the time being we do not introduce more complex garbage
    1430             :  * administration code.
    1431             :  *
    1432             :  * Also note that for top-level stack frames (no environment available),
    1433             :  * we should retain the value stack because it acts as a global variables.
    1434             :  * This situation is indicated by the 'global' in the stack frame.
    1435             :  * Upon termination of the session, the stack should be cleared.
    1436             :  * Beware that variables may be know polymorphic, their actual
    1437             :  * type should be saved for variables that recide on a global
    1438             :  * stack frame.
    1439             :  */
    1440      444605 : void garbageCollector(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int flag)
    1441             : {
    1442             :         int k;
    1443             :         ValPtr v;
    1444             : 
    1445      444605 :         assert(mb->vtop <= mb->vsize);
    1446      444605 :         assert(stk->stktop <= stk->stksize);
    1447             :         (void) flag;
    1448             :         (void)mb;
    1449             :         (void)cntxt;
    1450   110790895 :         for (k = 0; k < stk->stktop; k++) {
    1451             :         //      if (isVarCleanup(mb, k) ){
    1452   110346290 :                         garbageElement(cntxt, v = &stk->stk[k]);
    1453   110346290 :                         v->vtype = TYPE_int;
    1454   110346290 :                         v->val.ival = int_nil;
    1455             :         //      }
    1456             :         }
    1457      444605 : }

Generated by: LCOV version 1.14