LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_interpreter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 441 646 68.3 %
Date: 2024-04-25 20:03:45 Functions: 8 10 80.0 %

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

Generated by: LCOV version 1.14