LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_interpreter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 436 660 66.1 %
Date: 2024-04-26 00:35:57 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    36720084 : 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    36720084 :         return (ptr) &stk->stk[pci->argv[k]].val;
      43             : }
      44             : 
      45             : static str
      46    34631947 : malCommandCall(MalStkPtr stk, InstrPtr pci)
      47             : {
      48    34631947 :         str ret = MAL_SUCCEED;
      49             : 
      50    34631947 :         switch (pci->argc) {
      51           0 :         case 0:
      52           0 :                 ret = (*(str (*) (void)) pci->fcn)();
      53           0 :                 break;
      54     1010300 :         case 1:
      55     1010300 :                 ret = (*(str (*) (void *)) pci->fcn)(
      56             :                         getArgReference(stk, pci, 0));
      57     1010300 :                 break;
      58      140343 :         case 2:
      59      140343 :                 ret = (*(str (*) (void *, void *)) pci->fcn)(
      60             :                         getArgReference(stk, pci, 0),
      61             :                         getArgReference(stk, pci, 1));
      62      140343 :                 break;
      63    31368906 :         case 3:
      64    31368906 :                 ret = (*(str (*) (void *, void *, void *)) pci->fcn)(
      65             :                         getArgReference(stk, pci, 0),
      66             :                         getArgReference(stk, pci, 1),
      67             :                         getArgReference(stk, pci, 2));
      68    31368906 :                 break;
      69      639033 :         case 4:
      70      639033 :                 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      639033 :                 break;
      76      817669 :         case 5:
      77      817669 :                 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      817669 :                 break;
      84        4077 :         case 6:
      85        4077 :                 ret = (*(str (*) (void *, void *, void *, void *, void *,
      86        4077 :                                                   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        4077 :                 break;
      94      145194 :         case 7:
      95      145194 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
      96      145194 :                                                    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      145194 :                 break;
     105      484693 :         case 8:
     106      484693 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     107      484693 :                                                    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      484693 :                 break;
     117       21418 :         case 9:
     118       21418 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     119       21418 :                                                    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       21418 :                 break;
     130          30 :         case 10:
     131          30 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     132          30 :                                                    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          30 :                 break;
     144         177 :         case 11:
     145         177 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     146         177 :                                                    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         177 :                 break;
     159         107 :         case 12:
     160         107 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     161             :                                                    void *, void *, void *, void *, void *,
     162         107 :                                                    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         107 :                 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             :                                 lhs->bat = isaBatType(getVarType(mb, i));            \
     278             :                         }                                                                               \
     279             :                 }                                                                                       \
     280             :         } while (0)
     281             : 
     282             : static inline bool
     283    10298555 : isNotUsedIn(InstrPtr p, int start, int a)
     284             : {
     285    25311216 :         for (int k = start; k < p->argc; k++)
     286    15018094 :                 if (getArg(p, k) == a)
     287             :                         return false;
     288             :         return true;
     289             : }
     290             : 
     291             : MalStkPtr
     292      654177 : prepareMALstack(MalBlkPtr mb, int size)
     293             : {
     294      654177 :         MalStkPtr stk = NULL;
     295      654177 :         int res = 1;
     296      654177 :         ValPtr lhs, rhs;
     297             : 
     298      654177 :         stk = newGlobalStack(size);
     299      654271 :         if (!stk)
     300             :                 return NULL;
     301      654271 :         stk->stktop = mb->vtop;
     302      654271 :         stk->blk = mb;
     303      654271 :         stk->memory = 0;
     304   115555452 :         initStack(0, res);
     305      654258 :         if (!res) {
     306           0 :                 freeStack(stk);
     307           0 :                 return NULL;
     308             :         }
     309             :         return stk;
     310             : }
     311             : 
     312             : str
     313      563414 : runMAL(Client cntxt, MalBlkPtr mb, MalBlkPtr mbcaller, MalStkPtr env)
     314             : {
     315      563414 :         MalStkPtr stk = NULL;
     316      563414 :         ValPtr lhs, rhs;
     317      563414 :         str ret;
     318      563414 :         (void) mbcaller;
     319             : 
     320             :         /* Prepare a new interpreter call. This involves two steps, (1)
     321             :          * allocate the minimum amount of stack space needed, some slack
     322             :          * resources are included to permit code optimizers to add a few
     323             :          * variables at run time, (2) copying the arguments into the new
     324             :          * stack frame.
     325             :          *
     326             :          * The env stackframe is set when a MAL function is called
     327             :          * recursively.  Alternatively, there is no caller but a stk to be
     328             :          * re-used for interpretation.  We assume here that it aligns with
     329             :          * the variable table of the routine being called.
     330             :          *
     331             :          * allocate space for value stack the global stack should be large
     332             :          * enough
     333             :          */
     334      563414 :         cntxt->lastcmd = time(0);
     335      563417 :         ATOMIC_SET(&cntxt->lastprint, GDKusec());
     336      563422 :         if (env != NULL) {
     337        9868 :                 int res = 1;
     338        9868 :                 stk = env;
     339        9868 :                 if (mb != stk->blk)
     340           0 :                         throw(MAL, "mal.interpreter", "misalignment of symbols");
     341        9868 :                 if (mb->vtop > stk->stksize)
     342           0 :                         throw(MAL, "mal.interpreter", "stack too small");
     343       25910 :                 initStack(env->stkbot, res);
     344        9868 :                 if (!res)
     345           0 :                         throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     346             :         } else {
     347      553554 :                 stk = prepareMALstack(mb, mb->vsize);
     348      553543 :                 if (stk == 0)
     349           0 :                         throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     350      553543 :                 stk->blk = mb;
     351             :                 /*safeguardStack */
     352      553543 :                 if (env) {
     353             :                         stk->stkdepth = stk->stksize + env->stkdepth;
     354             :                         stk->calldepth = env->calldepth + 1;
     355             :                         stk->up = env;
     356             :                         if (stk->calldepth > 256)
     357             :                                 throw(MAL, "mal.interpreter", MAL_CALLDEPTH_FAIL);
     358             :                 }
     359             :                 /*
     360             :                  * An optimization is to copy all constant variables used in
     361             :                  * functions immediately onto the value stack. Then we do not
     362             :                  * have to check for their location later on any more. At some
     363             :                  * point, the effect is optimal, if at least several constants
     364             :                  * are referenced in a function (a gain on tst400a of 20% has
     365             :                  * been observed due the small size of the function).
     366             :                  */
     367             :         }
     368      563411 :         ret = runMALsequence(cntxt, mb, 1, 0, stk, env, 0);
     369             : 
     370      563423 :         if (!stk->keepAlive && garbageControl(getInstrPtr(mb, 0)))
     371      553555 :                 garbageCollector(cntxt, mb, stk, env != stk);
     372      563401 :         if (stk && stk != env)
     373      553529 :                 freeStack(stk);
     374      563419 :         if (ret == MAL_SUCCEED) {
     375      545387 :                 switch (cntxt->qryctx.endtime) {
     376           0 :                 case QRY_TIMEOUT:
     377           0 :                         throw(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     378           0 :                 case QRY_INTERRUPT:
     379           0 :                         throw(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
     380             :                 default:
     381             :                         break;
     382             :                 }
     383             :         }
     384             :         return ret;
     385             : }
     386             : 
     387             : /* Single instruction
     388             :  * It is possible to re-enter the interpreter at a specific place.
     389             :  * This is used in the area where we need to support co-routines.
     390             :  *
     391             :  * A special case for MAL interpretation is to execute just one instruction.
     392             :  * This is typically used by optimizers and schedulers that need part of the
     393             :  * answer to direct their actions. Or, a dataflow scheduler could step in
     394             :  * to enforce a completely different execution order.
     395             :  */
     396             : str
     397       60168 : reenterMAL(Client cntxt, MalBlkPtr mb, int startpc, int stoppc, MalStkPtr stk)
     398             : {
     399       60168 :         str ret;
     400       60168 :         int keepAlive;
     401             : 
     402       60168 :         if (stk == NULL)
     403           0 :                 throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     404       60168 :         keepAlive = stk->keepAlive;
     405       60168 :         ret = runMALsequence(cntxt, mb, startpc, stoppc, stk, 0, 0);
     406             : 
     407       60159 :         if (keepAlive == 0 && garbageControl(getInstrPtr(mb, 0)))
     408           0 :                 garbageCollector(cntxt, mb, stk, stk != 0);
     409             :         return ret;
     410             : }
     411             : 
     412             : /*
     413             :  * Front ends may benefit from a more direct call to any of the MAL
     414             :  * procedural abstractions. The argument list points to the arguments
     415             :  * for the block to be executed. An old stack frame may be re-used,
     416             :  * but it is then up to the caller to ensure it is properly
     417             :  * initialized.
     418             :  * The call does not return values, they are ignored.
     419             :  */
     420             : str
     421           0 : callMAL(Client cntxt, MalBlkPtr mb, MalStkPtr *env, ValPtr argv[])
     422             : {
     423           0 :         MalStkPtr stk = NULL;
     424           0 :         str ret = MAL_SUCCEED;
     425           0 :         ValPtr lhs;
     426           0 :         InstrPtr pci = getInstrPtr(mb, 0);
     427             : 
     428           0 :         cntxt->lastcmd = time(0);
     429             : 
     430           0 :         switch (pci->token) {
     431           0 :         case FUNCTIONsymbol:
     432             :         case FCNcall:
     433             :                 /*
     434             :                  * Prepare the stack frame for this operation. Copy all the arguments
     435             :                  * in place. We assume that the caller has supplied pointers for
     436             :                  * all arguments and return values.
     437             :                  */
     438           0 :                 if (*env == NULL) {
     439           0 :                         stk = prepareMALstack(mb, mb->vsize);
     440           0 :                         if (stk == NULL)
     441           0 :                                 throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     442           0 :                         stk->up = 0;
     443           0 :                         *env = stk;
     444             :                 } else {
     445             :                         ValPtr lhs, rhs;
     446             :                         int res = 1;
     447             : 
     448           0 :                         stk = *env;
     449           0 :                         initStack(0, res);
     450           0 :                         if (!res)
     451           0 :                                 throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     452             :                 }
     453           0 :                 assert(stk);
     454           0 :                 for (int i = pci->retc; i < pci->argc; i++) {
     455           0 :                         lhs = &stk->stk[pci->argv[i]];
     456           0 :                         if (VALcopy(lhs, argv[i]) == NULL)
     457           0 :                                 throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     458           0 :                         if (lhs->bat)
     459           0 :                                 BBPretain(lhs->val.bval);
     460             :                 }
     461           0 :                 ret = runMALsequence(cntxt, mb, 1, 0, stk, 0, 0);
     462           0 :                 break;
     463           0 :         case PATcall:
     464             :         case CMDcall:
     465             :         default:
     466           0 :                 throw(MAL, "mal.interpreter", RUNTIME_UNKNOWN_INSTRUCTION);
     467             :         }
     468           0 :         if (stk)
     469           0 :                 garbageCollector(cntxt, mb, stk, TRUE);
     470           0 :         if (ret == MAL_SUCCEED) {
     471           0 :                 switch (cntxt->qryctx.endtime) {
     472           0 :                 case QRY_TIMEOUT:
     473           0 :                         throw(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     474           0 :                 case QRY_INTERRUPT:
     475           0 :                         throw(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
     476             :                 default:
     477             :                         break;
     478             :                 }
     479             :         }
     480             :         return ret;
     481             : }
     482             : 
     483             : /*
     484             :  * The core of the interpreter is presented next. It takes the context
     485             :  * information and starts the interpretation at the designated
     486             :  * instruction.  Note that the stack frame is aligned and initialized
     487             :  * in the enclosing routine.  When we start executing the first
     488             :  * instruction, we take the wall-clock time for resource management.
     489             :  */
     490             : str
     491    12287954 : runMALsequence(Client cntxt, MalBlkPtr mb, int startpc,
     492             :                            int stoppc, MalStkPtr stk, MalStkPtr env, InstrPtr pcicaller)
     493             : {
     494    12287954 :         ValPtr lhs, rhs, v;
     495    12287954 :         InstrPtr pci = 0;
     496    12287954 :         int exceptionVar;
     497    12287954 :         str ret = MAL_SUCCEED, localGDKerrbuf = GDKerrbuf;
     498    12286758 :         ValRecord backups[16];
     499    12286758 :         ValPtr backup;
     500    12286758 :         int garbages[16], *garbage;
     501    12286758 :         int stkpc = 0;
     502    12286758 :         RuntimeProfileRecord runtimeProfile, runtimeProfileFunction;
     503    12286758 :         lng lastcheck = 0;
     504    12286758 :         bool startedProfileQueue = false;
     505             : #define CHECKINTERVAL 1000              /* how often do we check for client disconnect */
     506    12286758 :         runtimeProfile.ticks = runtimeProfileFunction.ticks = 0;
     507             : 
     508    12286758 :         if (stk == NULL)
     509           0 :                 throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     510             : 
     511             :         /* prepare extended backup and garbage structures */
     512    12286758 :         if (startpc + 1 == stoppc) {
     513    11649538 :                 pci = getInstrPtr(mb, startpc);
     514    11649538 :                 if (pci->argc > 16) {
     515      128635 :                         backup = GDKmalloc(pci->argc * sizeof(ValRecord));
     516      128394 :                         garbage = (int *) GDKzalloc(pci->argc * sizeof(int));
     517      128470 :                         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    11520903 :                         backup = backups;
     524    11520903 :                         garbage = garbages;
     525    11520903 :                         memset(garbages, 0, sizeof(garbages));
     526             :                 }
     527      637220 :         } else if (mb->maxarg > 16) {
     528       91779 :                 backup = GDKmalloc(mb->maxarg * sizeof(ValRecord));
     529       91779 :                 garbage = (int *) GDKzalloc(mb->maxarg * sizeof(int));
     530       91779 :                 if (backup == NULL || garbage == NULL) {
     531           0 :                         GDKfree(backup);
     532           0 :                         GDKfree(garbage);
     533           0 :                         throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     534             :                 }
     535             :         } else {
     536      545441 :                 backup = backups;
     537      545441 :                 garbage = garbages;
     538      545441 :                 memset(garbages, 0, sizeof(garbages));
     539             :         }
     540             : 
     541             :         /* also produce event record for start of function */
     542    12286593 :         if (startpc == 1 && startpc < mb->stop) {
     543      637217 :                 startedProfileQueue = true;
     544      637217 :                 runtimeProfileInit(cntxt, mb, stk);
     545      637249 :                 runtimeProfileBegin(cntxt, mb, stk, getInstrPtr(mb, 0),
     546             :                                                         &runtimeProfileFunction);
     547      637250 :                 if (cntxt->sessiontimeout
     548      122039 :                         && cntxt->qryctx.starttime - cntxt->session >
     549             :                         cntxt->sessiontimeout) {
     550           0 :                         runtimeProfileFinish(cntxt, mb, stk);
     551           0 :                         if (backup != backups)
     552           0 :                                 GDKfree(backup);
     553           0 :                         if (garbage != garbages)
     554           0 :                                 GDKfree(garbage);
     555           0 :                         throw(MAL, "mal.interpreter",
     556             :                                   SQLSTATE(HYT00) RUNTIME_SESSION_TIMEOUT);
     557             :                 }
     558             :         }
     559    12286626 :         stkpc = startpc;
     560    12286626 :         exceptionVar = -1;
     561             : 
     562    69025056 :         while (stkpc < mb->stop && stkpc != stoppc) {
     563             :                 // incomplete block being executed, requires at least signature and end statement
     564    56873064 :                 MT_thread_setalgorithm(NULL);
     565    56781687 :                 pci = getInstrPtr(mb, stkpc);
     566    56781687 :                 if (cntxt->mode == FINISHCLIENT) {
     567           1 :                         stkpc = stoppc;
     568           1 :                         if (ret == MAL_SUCCEED)
     569           1 :                                 ret = createException(MAL, "mal.interpreter",
     570             :                                                                           "prematurely stopped client");
     571             :                         break;
     572             :                 }
     573             : 
     574    56781686 :                 if (stk->status) {
     575             :                         /* pause procedure from SYSMON */
     576           1 :                         if (stk->status == 'p') {
     577           0 :                                 while (stk->status == 'p')
     578           0 :                                         MT_sleep_ms(50);
     579           0 :                                 continue;
     580             :                         }
     581             :                         /* stop procedure from SYSMON */
     582           1 :                         if (stk->status == 'q') {
     583           1 :                                 stkpc = mb->stop;
     584           1 :                                 ret = createException(MAL, "mal.interpreter",
     585             :                                                                           "Query with tag " OIDFMT
     586             :                                                                           " received stop signal", mb->tag);
     587           1 :                                 break;
     588             :                         }
     589             :                 }
     590             :                 //Ensure we spread system resources over multiple users as well.
     591    56781685 :                 runtimeProfileBegin(cntxt, mb, stk, pci, &runtimeProfile);
     592    56763077 :                 if (runtimeProfile.ticks > lastcheck + CHECKINTERVAL) {
     593    12310841 :                         if (cntxt->fdin && !mnstr_isalive(cntxt->fdin->s)) {
     594           0 :                                 cntxt->mode = FINISHCLIENT;
     595           0 :                                 stkpc = stoppc;
     596           0 :                                 ret = createException(MAL, "mal.interpreter",
     597             :                                                                           "prematurely stopped client");
     598           0 :                                 break;
     599             :                         }
     600    12204248 :                         lastcheck = runtimeProfile.ticks;
     601             :                 }
     602             : 
     603    56656484 :                 if (qptimeout > 0) {
     604           0 :                         lng t = GDKusec();
     605           0 :                         ATOMIC_BASE_TYPE lp = ATOMIC_GET(&cntxt->lastprint);
     606           0 :                         if ((lng) lp + qptimeout < t) {
     607             :                                 /* if still the same, replace lastprint with current
     608             :                                  * time and print the query */
     609           0 :                                 if (ATOMIC_CAS(&cntxt->lastprint, &lp, t)) {
     610           0 :                                         const char *q = cntxt->query ? cntxt->query : NULL;
     611           0 :                                         TRC_INFO(MAL_SERVER,
     612             :                                                          "%s: query already running " LLFMT "s: %.200s\n",
     613             :                                                          cntxt->mythread ? cntxt->mythread : "?",
     614             :                                                          (lng) (time(0) - cntxt->lastcmd), q ? q : "");
     615             :                                 }
     616             :                         }
     617             :                 }
     618             : 
     619             :                 /* The interpreter loop
     620             :                  * The interpreter is geared towards execution a MAL
     621             :                  * procedure together with all its descendant
     622             :                  * invocations. As such, it provides the MAL abtract
     623             :                  * machine processor.
     624             :                  *
     625             :                  * The value-stack frame of the surrounding scope is
     626             :                  * needed to resolve binding values.  Getting (putting) a
     627             :                  * value from (into) a surrounding scope should be guarded
     628             :                  * with the exclusive access lock.  This situation is
     629             :                  * encapsulated by a bind() function call, whose
     630             :                  * parameters contain the access mode required.
     631             :                  *
     632             :                  * The formal procedure arguments are assumed to always
     633             :                  * occupy the first elements in the value stack.
     634             :                  *
     635             :                  * Before we execute an instruction the variables to be
     636             :                  * garbage collected are identified. In the post-execution
     637             :                  * phase they are removed.
     638             :                  */
     639   113899434 :                 for (int i = 0; i < pci->retc; i++)
     640    57242950 :                         backup[i] = stk->stk[getArg(pci, i)];
     641             : 
     642    56656484 :                 if (garbageControl(pci)) {
     643   140302569 :                         for (int i = 0; i < pci->argc; i++) {
     644   110279358 :                                 int a = getArg(pci, i);
     645             : 
     646   110279358 :                                 if (stk->stk[a].bat && getEndScope(mb, a) == stkpc
     647    20597110 :                                         && isNotUsedIn(pci, i + 1, a))
     648    10297225 :                                         garbage[i] = a;
     649             :                                 else
     650    99982133 :                                         garbage[i] = -1;
     651             :                         }
     652             :                 }
     653             : 
     654    56656484 :                 freeException(ret);
     655    56689432 :                 ret = MAL_SUCCEED;
     656    56689432 :                 switch (pci->token) {
     657     3511161 :                 case ASSIGNsymbol:
     658             :                         /* Assignment command
     659             :                          * The assignment statement copies values around on
     660             :                          * the stack frame, including multiple assignments.
     661             :                          *
     662             :                          * Pushing constants/initial values onto the stack is
     663             :                          * a separate operation.  It takes the constant value
     664             :                          * discovered at compile time and stored in the symbol
     665             :                          * table and moves it to the stackframe location. This
     666             :                          * activity is made part of the start-up procedure.
     667             :                          *
     668             :                          * The before after calls should be reconsidered here,
     669             :                          * because their. They seem superflous and the way
     670             :                          * they are used will cause errors in multi-assignment
     671             :                          * statements.
     672             :                          */
     673     6976451 :                         for (int k = 0, i = pci->retc; k < pci->retc && i < pci->argc;
     674     3465290 :                                  i++, k++) {
     675     3465205 :                                 lhs = &stk->stk[pci->argv[k]];
     676     3465205 :                                 assert(lhs->bat == isaBatType(getArgType(mb, pci, k)));
     677     3465205 :                                 rhs = &stk->stk[pci->argv[i]];
     678     3465205 :                                 assert(rhs->bat == isaBatType(getArgType(mb, pci, i)));
     679     3465205 :                                 if (VALcopy(lhs, rhs) == NULL) {
     680           0 :                                         ret = createException(MAL, "mal.interpreter",
     681             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     682           0 :                                         break;
     683     3465289 :                                 } else if (lhs->bat && !is_bat_nil(lhs->val.bval))
     684        4177 :                                         BBPretain(lhs->val.bval);
     685             :                         }
     686             :                         break;
     687    17924369 :                 case PATcall:
     688    17924369 :                         if (pci->fcn == NULL) {
     689           0 :                                 ret = createException(MAL, "mal.interpreter",
     690             :                                                                           "address of pattern %s.%s missing",
     691             :                                                                           pci->modname, pci->fcnname);
     692             :                         } else {
     693    17924369 :                                 TRC_DEBUG(ALGO, "calling %s.%s\n",
     694             :                                                   pci->modname ? pci->modname : "<null>",
     695             :                                                   pci->fcnname ? pci->fcnname : "<null>");
     696    17924369 :                                 ret = (*(str (*) (Client, MalBlkPtr, MalStkPtr, InstrPtr)) pci->
     697             :                                            fcn) (cntxt, mb, stk, pci);
     698             : #ifndef NDEBUG
     699    17931506 :                                 if (ret == MAL_SUCCEED) {
     700             :                                         /* check that the types of actual results match
     701             :                                          * expected results */
     702    36520223 :                                         for (int i = 0; i < pci->retc; i++) {
     703    18562184 :                                                 int a = getArg(pci, i);
     704    18562184 :                                                 int t = getArgType(mb, pci, i);
     705             : 
     706    18562184 :                                                 if (isaBatType(t)) {
     707     6072353 :                                                         bat bid = stk->stk[a].val.bval;
     708     6072353 :                                                         BAT *_b;
     709     6072353 :                                                         t = getBatType(t);
     710     6072353 :                                                         assert(stk->stk[a].bat);
     711    17679439 :                                                         assert(is_bat_nil(bid) ||
     712             :                                                                    t == TYPE_any ||
     713             :                                                                    ((_b = BBP_desc(bid)) != NULL &&
     714             :                                                                         ATOMtype(_b->ttype) == ATOMtype(t)));
     715             :                                                 } else {
     716    12489831 :                                                         assert(t == stk->stk[a].vtype);
     717             :                                                 }
     718             :                                         }
     719             :                                 }
     720             : #endif
     721             :                         }
     722             :                         break;
     723    34628999 :                 case CMDcall:
     724    34628999 :                         TRC_DEBUG(ALGO, "calling %s.%s\n",
     725             :                                           pci->modname ? pci->modname : "<null>",
     726             :                                           pci->fcnname ? pci->fcnname : "<null>");
     727    34628999 :                         ret = malCommandCall(stk, pci);
     728             : #ifndef NDEBUG
     729    34625320 :                         if (ret == MAL_SUCCEED) {
     730             :                                 /* check that the types of actual results match
     731             :                                  * expected results */
     732    69739092 :                                 for (int i = 0; i < pci->retc; i++) {
     733    35102587 :                                         int a = getArg(pci, i);
     734    35102587 :                                         int t = getArgType(mb, pci, i);
     735             : 
     736    35102587 :                                         if (isaBatType(t)) {
     737             :                                                 //bat bid = stk->stk[a].val.bval;
     738    19400938 :                                                 t = getBatType(t);
     739    19400938 :                                                 assert(stk->stk[a].bat);
     740             :                                                 //assert( !is_bat_nil(bid));
     741    19400938 :                                                 assert(t != TYPE_any);
     742             :                                                 //assert( ATOMtype(BBP_desc(bid)->ttype) == ATOMtype(t));
     743             :                                         } else {
     744    15701649 :                                                 assert(t == stk->stk[a].vtype);
     745             :                                         }
     746             :                                 }
     747             :                         }
     748             : #endif
     749             :                         break;
     750       73777 :                 case FCNcall: {
     751             :                         /*
     752             :                          * MAL function calls are relatively expensive,
     753             :                          * because they have to assemble a new stack frame and
     754             :                          * do housekeeping, such as garbagecollection of all
     755             :                          * non-returned values.
     756             :                          */
     757       73777 :                         MalStkPtr nstk;
     758       73777 :                         InstrPtr q;
     759       73777 :                         int ii, arg;
     760             : 
     761       73777 :                         nstk = prepareMALstack(pci->blk, pci->blk->vsize);
     762       73784 :                         if (nstk == 0) {
     763           0 :                                 ret = createException(MAL, "mal.interpreter", MAL_STACK_FAIL);
     764           0 :                                 break;
     765             :                         }
     766       73784 :                         nstk->pcup = stkpc;
     767             : 
     768             :                         /*safeguardStack */
     769       73784 :                         nstk->stkdepth = nstk->stksize + stk->stkdepth;
     770       73784 :                         nstk->calldepth = stk->calldepth + 1;
     771       73784 :                         nstk->up = stk;
     772       73784 :                         if (nstk->calldepth > 256) {
     773           1 :                                 ret = createException(MAL, "mal.interpreter",
     774             :                                                                           MAL_CALLDEPTH_FAIL);
     775           1 :                                 GDKfree(nstk);
     776           1 :                                 break;
     777             :                         }
     778       73783 :                         if ((unsigned) nstk->stkdepth >
     779       46006 :                                 THREAD_STACK_SIZE / sizeof(mb->var[0]) / 4 && THRhighwater()) {
     780             :                                 /* we are running low on stack space */
     781           0 :                                 ret = createException(MAL, "mal.interpreter", MAL_STACK_FAIL);
     782           0 :                                 GDKfree(nstk);
     783           0 :                                 break;
     784             :                         }
     785             : 
     786             :                         /* copy arguments onto destination stack */
     787       73783 :                         q = getInstrPtr(pci->blk, 0);
     788       73783 :                         arg = q->retc;
     789      378253 :                         for (ii = pci->retc; ii < pci->argc; ii++, arg++) {
     790      304470 :                                 lhs = &nstk->stk[q->argv[arg]];
     791      304470 :                                 rhs = &stk->stk[pci->argv[ii]];
     792      304470 :                                 if (VALcopy(lhs, rhs) == NULL) {
     793           0 :                                         GDKfree(nstk);
     794           0 :                                         ret = createException(MAL, "mal.interpreter",
     795             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     796           0 :                                         break;
     797      304470 :                                 } else if (lhs->bat)
     798          18 :                                         BBPretain(lhs->val.bval);
     799             :                         }
     800       73783 :                         if (ret == MAL_SUCCEED && ii == pci->argc) {
     801       73783 :                                 ret = runMALsequence(cntxt, pci->blk, 1, pci->blk->stop, nstk,
     802             :                                                                          stk, pci);
     803       73783 :                                 garbageCollector(cntxt, pci->blk, nstk, 0);
     804       73783 :                                 arg = q->retc;
     805      378253 :                                 for (ii = pci->retc; ii < pci->argc; ii++, arg++) {
     806      304470 :                                         lhs = &nstk->stk[q->argv[arg]];
     807      304470 :                                         if (lhs->bat)
     808           0 :                                                 BBPrelease(lhs->val.bval);
     809             :                                 }
     810       73783 :                                 GDKfree(nstk);
     811             :                         }
     812             :                         break;
     813             :                 }
     814             :                 case REMsymbol:
     815             :                         break;
     816      551028 :                 case ENDsymbol:
     817      551028 :                         runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
     818      550981 :                         runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb, 0),
     819             :                                                            &runtimeProfileFunction);
     820      551157 :                         if (pcicaller && garbageControl(getInstrPtr(mb, 0)))
     821        5994 :                                 garbageCollector(cntxt, mb, stk, TRUE);
     822      551157 :                         if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
     823           0 :                                 freeException(ret);     /* overrule exception */
     824           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     825           0 :                                 break;
     826      551157 :                         } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
     827           0 :                                 freeException(ret);     /* overrule exception */
     828           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
     829           0 :                                 break;
     830             :                         }
     831      551157 :                         stkpc = mb->stop;    // force end of loop
     832      551157 :                         continue;
     833           0 :                 default: {
     834           0 :                         str w;
     835           0 :                         if (pci->token < 0) {
     836             :                                 /* temporary NOOP instruction */
     837             :                                 break;
     838             :                         }
     839           0 :                         w = instruction2str(mb, 0, pci, FALSE);
     840           0 :                         if (w) {
     841           0 :                                 ret = createException(MAL, "interpreter", "unkown operation:%s",
     842             :                                                                           w);
     843           0 :                                 GDKfree(w);
     844             :                         } else {
     845           0 :                                 ret = createException(MAL, "interpreter",
     846             :                                                                           "failed instruction2str");
     847             :                         }
     848             :                         // runtimeProfileBegin already sets the time in the instruction
     849           0 :                         if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
     850           0 :                                 freeException(ret);     /* overrule exception */
     851           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     852           0 :                                 break;
     853           0 :                         } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
     854           0 :                                 freeException(ret);     /* overrule exception */
     855           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
     856           0 :                                 break;
     857             :                         }
     858             : 
     859           0 :                         stkpc = mb->stop;
     860           0 :                         continue;
     861             :                 }
     862             :                 }
     863             : 
     864             :                 /* monitoring information should reflect the input arguments,
     865             :                    which may be removed by garbage collection  */
     866             :                 /* BEWARE, the SQL engine or MAL function could zap the block, leaving garbage behind in pci */
     867             :                 /* this hack means we loose a closing event */
     868    56141954 :                 if (mb->stop <= 1)
     869           0 :                         continue;
     870    56141954 :                 runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
     871             :                 /* when we find a timeout situation, then the result is already known
     872             :                  * and assigned,  the backup version is not removed*/
     873    56173127 :                 if (ret == MAL_SUCCEED) {
     874   113416197 :                         for (int i = 0; i < pci->retc; i++) {
     875    57344642 :                                 lhs = &backup[i];
     876    57344642 :                                 if (lhs->bat) {
     877    25544160 :                                         BBPrelease(lhs->val.bval);
     878    31800482 :                                 } else if (ATOMextern(lhs->vtype) &&
     879     1836003 :                                         lhs->val.pval &&
     880      139379 :                                         lhs->val.pval != ATOMnilptr(lhs->vtype) &&
     881      139379 :                                         lhs->val.pval != stk->stk[getArg(pci, i)].val.pval)
     882      137093 :                                         GDKfree(lhs->val.pval);
     883             :                         }
     884    56071555 :                         if (ATOMIC_GET(&GDKdebug) & CHECKMASK && exceptionVar < 0) {
     885             :                                 BAT *b;
     886             : 
     887   113258173 :                                 for (int i = 0; i < pci->retc; i++) {
     888    57208125 :                                         if (garbage[i] == -1
     889    55411897 :                                                 && stk->stk[getArg(pci, i)].bat
     890    25009527 :                                                 && !is_bat_nil(stk->stk[getArg(pci, i)].val.bval)) {
     891    24959962 :                                                 assert(stk->stk[getArg(pci, i)].val.bval > 0);
     892    24959962 :                                                 b = BATdescriptor(stk->stk[getArg(pci, i)].val.bval);
     893    25041574 :                                                 if (b == NULL) {
     894           0 :                                                         if (ret == MAL_SUCCEED)
     895           0 :                                                                 ret = createException(MAL, "mal.propertyCheck",
     896             :                                                                                                           SQLSTATE(HY002)
     897             :                                                                                                           RUNTIME_OBJECT_MISSING);
     898           0 :                                                         continue;
     899             :                                                 }
     900    25041574 :                                                 BATassertProps(b);
     901    25027875 :                                                 BBPunfix(b->batCacheid);
     902             :                                         }
     903             :                                 }
     904             :                         }
     905             : 
     906             :                         /* general garbage collection */
     907    56098192 :                         if (ret == MAL_SUCCEED && garbageControl(pci)) {
     908   141016256 :                                 for (int i = 0; i < pci->argc; i++) {
     909   111014518 :                                         int a = getArg(pci, i);
     910             : 
     911   111014518 :                                         if (isaBatType(getArgType(mb, pci, i))) {
     912    62220255 :                                                 bat bid = stk->stk[a].val.bval;
     913             : 
     914    62220255 :                                                 if (garbage[i] >= 0) {
     915    10280301 :                                                         bid = stk->stk[garbage[i]].val.bval;
     916    10280301 :                                                         if (!is_bat_nil(bid)) {
     917     9883856 :                                                                 stk->stk[garbage[i]].val.bval = bat_nil;
     918     9883856 :                                                                 BBPcold(bid);
     919     9863199 :                                                                 BBPrelease(bid);
     920             :                                                         }
     921             :                                                 }
     922             :                                         }
     923             :                                 }
     924             :                         }
     925             :                 }
     926             : 
     927             :                 /* Exception handling */
     928    56187270 :                 if (localGDKerrbuf && localGDKerrbuf[0]) {
     929           2 :                         if (ret == MAL_SUCCEED)
     930           2 :                                 ret = createException(MAL, "mal.interpreter", GDK_EXCEPTION);
     931             :                         // TODO take properly care of the GDK exception
     932           2 :                         localGDKerrbuf[0] = 0;
     933             :                 }
     934             : 
     935    56187270 :                 if (ret != MAL_SUCCEED) {
     936       19267 :                         str msg = 0;
     937             : 
     938             :                         /* Detect any exception received from the implementation. */
     939             :                         /* The first identifier is an optional exception name */
     940       19267 :                         if (strstr(ret, "!skip-to-end")) {
     941           0 :                                 freeException(ret);
     942           0 :                                 ret = MAL_SUCCEED;
     943           0 :                                 stkpc = mb->stop;
     944           0 :                                 continue;
     945             :                         }
     946             :                         /*
     947             :                          * Exceptions are caught based on their name, which is part of the
     948             :                          * exception message. The ANYexception variable catches all.
     949             :                          */
     950       19267 :                         exceptionVar = -1;
     951       19267 :                         msg = strchr(ret, ':');
     952       19267 :                         if (msg) {
     953       19267 :                                 exceptionVar = findVariableLength(mb, ret, (int) (msg - ret));
     954             :                         }
     955       19270 :                         if (exceptionVar == -1)
     956       19268 :                                 exceptionVar = findVariableLength(mb, "ANYexception", 12);
     957             : 
     958             :                         /* unknown exceptions lead to propagation */
     959       19268 :                         if (exceptionVar == -1) {
     960       19253 :                                 if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
     961          11 :                                         freeException(ret);     /* overrule exception */
     962          11 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     963       19242 :                                 } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
     964           0 :                                         freeException(ret);     /* overrule exception */
     965           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
     966             :                                 }
     967       19253 :                                 stkpc = mb->stop;
     968       19253 :                                 continue;
     969             :                         }
     970             :                         /* assure correct variable type */
     971          17 :                         if (getVarType(mb, exceptionVar) == TYPE_str) {
     972             :                                 /* watch out for concurrent access */
     973          17 :                                 MT_lock_set(&mal_contextLock);
     974          17 :                                 v = &stk->stk[exceptionVar];
     975          17 :                                 if (v->val.sval)
     976           5 :                                         freeException(v->val.sval);  /* old exception */
     977          17 :                                 VALset(v, TYPE_str, ret);
     978          17 :                                 ret = MAL_SUCCEED;
     979          17 :                                 MT_lock_unset(&mal_contextLock);
     980             :                         } else {
     981           0 :                                 mnstr_printf(cntxt->fdout, "%s", ret);
     982           0 :                                 freeException(ret);
     983           0 :                                 ret = MAL_SUCCEED;
     984             :                         }
     985             :                         /* position yourself at the catch instruction for further decisions */
     986             :                         /* skipToCatch(exceptionVar,@2,@3) */
     987             :                         /* skip to catch block or end */
     988         187 :                         for (; stkpc < mb->stop; stkpc++) {
     989         187 :                                 InstrPtr l = getInstrPtr(mb, stkpc);
     990         187 :                                 if (l->barrier == CATCHsymbol) {
     991             :                                         int j;
     992          17 :                                         for (j = 0; j < l->retc; j++)
     993          17 :                                                 if (getArg(l, j) == exceptionVar)
     994             :                                                         break;
     995           0 :                                                 else if (getArgName(mb, l, j) && strcmp(getArgName(mb, l, j), "ANYexception") == 0)
     996             :                                                         break;
     997          17 :                                         if (j < l->retc)
     998             :                                                 break;
     999             :                                 }
    1000             :                         }
    1001          17 :                         if (stkpc == mb->stop) {
    1002           0 :                                 if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
    1003           0 :                                         freeException(ret);     /* overrule exception */
    1004           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
    1005           0 :                                         stkpc = mb->stop;
    1006           0 :                                 } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
    1007           0 :                                         freeException(ret);     /* overrule exception */
    1008           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
    1009           0 :                                         stkpc = mb->stop;
    1010             :                                 }
    1011           0 :                                 continue;
    1012             :                         }
    1013          17 :                         pci = getInstrPtr(mb, stkpc);
    1014             :                 }
    1015             : 
    1016             :                 /*
    1017             :                  * After the expression has been evaluated we should check for
    1018             :                  * a possible change in the control flow.
    1019             :                  */
    1020    56168020 :                 switch (pci->barrier) {
    1021     1363930 :                 case BARRIERsymbol:
    1022     1363930 :                         v = &stk->stk[getDestVar(pci)];
    1023             :                         /* skip to end of barrier, depends on the type */
    1024     1363930 :                         switch (v->vtype) {
    1025     1363096 :                         case TYPE_bit:
    1026     1363096 :                                 if (v->val.btval == FALSE || is_bit_nil(v->val.btval))
    1027     1314865 :                                         stkpc = pci->jump;
    1028             :                                 break;
    1029           0 :                         case TYPE_bte:
    1030           0 :                                 if (is_bte_nil(v->val.btval))
    1031           0 :                                         stkpc = pci->jump;
    1032             :                                 break;
    1033         809 :                         case TYPE_oid:
    1034         809 :                                 if (is_oid_nil(v->val.oval))
    1035         599 :                                         stkpc = pci->jump;
    1036             :                                 break;
    1037           0 :                         case TYPE_sht:
    1038           0 :                                 if (is_sht_nil(v->val.shval))
    1039           0 :                                         stkpc = pci->jump;
    1040             :                                 break;
    1041           9 :                         case TYPE_int:
    1042           9 :                                 if (is_int_nil(v->val.ival))
    1043           0 :                                         stkpc = pci->jump;
    1044             :                                 break;
    1045          15 :                         case TYPE_lng:
    1046          15 :                                 if (is_lng_nil(v->val.lval))
    1047           0 :                                         stkpc = pci->jump;
    1048             :                                 break;
    1049             : #ifdef HAVE_HGE
    1050           0 :                         case TYPE_hge:
    1051           0 :                                 if (is_hge_nil(v->val.hval))
    1052           0 :                                         stkpc = pci->jump;
    1053             :                                 break;
    1054             : #endif
    1055           1 :                         case TYPE_flt:
    1056           1 :                                 if (is_flt_nil(v->val.fval))
    1057           0 :                                         stkpc = pci->jump;
    1058             :                                 break;
    1059           0 :                         case TYPE_dbl:
    1060           0 :                                 if (is_dbl_nil(v->val.dval))
    1061           0 :                                         stkpc = pci->jump;
    1062             :                                 break;
    1063           0 :                         case TYPE_str:
    1064           0 :                                 if (strNil(v->val.sval))
    1065           0 :                                         stkpc = pci->jump;
    1066             :                                 break;
    1067           0 :                         default: {
    1068           0 :                                 char name[IDLENGTH] = { 0 };
    1069           0 :                                 ret = createException(MAL, "mal.interpreter",
    1070             :                                                                           "%s: Unknown barrier type", getVarNameIntoBuffer(mb,
    1071             :                                                                                                                                                          getDestVar
    1072             :                                                                                                                                                          (pci), name));
    1073             :                                          }
    1074             :                         }
    1075     1363930 :                         stkpc++;
    1076     1363930 :                         break;
    1077    14255341 :                 case LEAVEsymbol:
    1078             :                 case REDOsymbol:
    1079    14255341 :                         v = &stk->stk[getDestVar(pci)];
    1080             :                         /* skip to end of barrier, depending on the type */
    1081    14255341 :                         switch (v->vtype) {
    1082         852 :                         case TYPE_bit:
    1083         852 :                                 if (v->val.btval == TRUE)
    1084         439 :                                         stkpc = pci->jump;
    1085             :                                 else
    1086         413 :                                         stkpc++;
    1087             :                                 break;
    1088           0 :                         case TYPE_str:
    1089           0 :                                 if (!strNil(v->val.sval))
    1090           0 :                                         stkpc = pci->jump;
    1091             :                                 else
    1092           0 :                                         stkpc++;
    1093             :                                 break;
    1094       44115 :                         case TYPE_oid:
    1095       44115 :                                 if (!is_oid_nil(v->val.oval))
    1096       43910 :                                         stkpc = pci->jump;
    1097             :                                 else
    1098         205 :                                         stkpc++;
    1099             :                                 break;
    1100           0 :                         case TYPE_sht:
    1101           0 :                                 if (!is_sht_nil(v->val.shval))
    1102           0 :                                         stkpc = pci->jump;
    1103             :                                 else
    1104           0 :                                         stkpc++;
    1105             :                                 break;
    1106         119 :                         case TYPE_int:
    1107         119 :                                 if (!is_int_nil(v->val.ival))
    1108         114 :                                         stkpc = pci->jump;
    1109             :                                 else
    1110           5 :                                         stkpc++;
    1111             :                                 break;
    1112           0 :                         case TYPE_bte:
    1113           0 :                                 if (!is_bte_nil(v->val.btval))
    1114           0 :                                         stkpc = pci->jump;
    1115             :                                 else
    1116           0 :                                         stkpc++;
    1117             :                                 break;
    1118    14210253 :                         case TYPE_lng:
    1119    14210253 :                                 if (!is_lng_nil(v->val.lval))
    1120    14210238 :                                         stkpc = pci->jump;
    1121             :                                 else
    1122          15 :                                         stkpc++;
    1123             :                                 break;
    1124             : #ifdef HAVE_HGE
    1125           0 :                         case TYPE_hge:
    1126           0 :                                 if (!is_hge_nil(v->val.hval))
    1127           0 :                                         stkpc = pci->jump;
    1128             :                                 else
    1129           0 :                                         stkpc++;
    1130             :                                 break;
    1131             : #endif
    1132           2 :                         case TYPE_flt:
    1133           2 :                                 if (!is_flt_nil(v->val.fval))
    1134           1 :                                         stkpc = pci->jump;
    1135             :                                 else
    1136           1 :                                         stkpc++;
    1137             :                                 break;
    1138           0 :                         case TYPE_dbl:
    1139           0 :                                 if (!is_dbl_nil(v->val.dval))
    1140           0 :                                         stkpc = pci->jump;
    1141             :                                 else
    1142           0 :                                         stkpc++;
    1143             :                                 break;
    1144             :                         default:
    1145             :                                 break;
    1146             :                         }
    1147             :                         break;
    1148          39 :                 case CATCHsymbol:
    1149             :                         /* catch blocks are skipped unless
    1150             :                            searched for explicitly */
    1151          39 :                         if (exceptionVar < 0) {
    1152          19 :                                 stkpc = pci->jump;
    1153          19 :                                 break;
    1154             :                         }
    1155          20 :                         exceptionVar = -1;
    1156          20 :                         stkpc++;
    1157          20 :                         break;
    1158       48357 :                 case EXITsymbol:
    1159       48357 :                         if (getDestVar(pci) == exceptionVar)
    1160           0 :                                 exceptionVar = -1;
    1161       48357 :                         stkpc++;
    1162       48357 :                         break;
    1163          16 :                 case RAISEsymbol:
    1164          16 :                         exceptionVar = getDestVar(pci);
    1165             :                         //freeException(ret);
    1166          16 :                         ret = MAL_SUCCEED;
    1167          16 :                         if (getVarType(mb, getDestVar(pci)) == TYPE_str) {
    1168          14 :                                 char nme[256];
    1169          14 :                                 snprintf(nme, 256, "%s.%s[%d]", getModuleId(getInstrPtr(mb, 0)),
    1170          14 :                                                  getFunctionId(getInstrPtr(mb, 0)), stkpc);
    1171          14 :                                 ret = createException(MAL, nme, "%s",
    1172          14 :                                                                           stk->stk[getDestVar(pci)].val.sval);
    1173             :                         }
    1174             :                         /* skipToCatch(exceptionVar, @2, stk) */
    1175             :                         /* skip to catch block or end */
    1176         362 :                         for (; stkpc < mb->stop; stkpc++) {
    1177         349 :                                 InstrPtr l = getInstrPtr(mb, stkpc);
    1178         349 :                                 if (l->barrier == CATCHsymbol) {
    1179             :                                         int j;
    1180           3 :                                         for (j = 0; j < l->retc; j++)
    1181           3 :                                                 if (getArg(l, j) == exceptionVar)
    1182             :                                                         break;
    1183           0 :                                                 else if (getArgName(mb, l, j) && strcmp(getArgName(mb, l, j), "ANYexception") == 0)
    1184             :                                                         break;
    1185           3 :                                         if (j < l->retc)
    1186             :                                                 break;
    1187             :                                 }
    1188             :                         }
    1189          16 :                         if (stkpc == mb->stop) {
    1190          13 :                                 runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
    1191          13 :                                 runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb, 0),
    1192             :                                                                    &runtimeProfileFunction);
    1193          13 :                                 break;
    1194             :                         }
    1195             :                         break;
    1196       67535 :                 case RETURNsymbol:
    1197             :                         /* a fake multi-assignment */
    1198       67535 :                         if (env != NULL && pcicaller != NULL) {
    1199             :                                 InstrPtr pp = pci;
    1200      137531 :                                 pci = pcicaller;
    1201      137531 :                                 for (int i = 0; i < pci->retc; i++) {
    1202       69998 :                                         rhs = &stk->stk[pp->argv[i]];
    1203       69998 :                                         lhs = &env->stk[pci->argv[i]];
    1204       69998 :                                         if (VALcopy(lhs, rhs) == NULL) {
    1205           0 :                                                 ret = createException(MAL, "mal.interpreter",
    1206             :                                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1207           0 :                                                 break;
    1208       69998 :                                         } else if (lhs->bat)
    1209        2916 :                                                 BBPretain(lhs->val.bval);
    1210             :                                 }
    1211       67533 :                                 if (garbageControl(getInstrPtr(mb, 0)))
    1212       67494 :                                         garbageCollector(cntxt, mb, stk, TRUE);
    1213             :                                 /* reset the clock */
    1214       67533 :                                 runtimeProfileExit(cntxt, mb, stk, pp, &runtimeProfile);
    1215       67533 :                                 runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb, 0),
    1216             :                                                                    &runtimeProfileFunction);
    1217             :                         }
    1218       67535 :                         stkpc = mb->stop;
    1219       67535 :                         continue;
    1220    40432802 :                 default:
    1221    40432802 :                         stkpc++;
    1222             :                 }
    1223    56100485 :                 if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
    1224           0 :                         if (ret == MAL_SUCCEED)
    1225           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
    1226           0 :                         stkpc = mb->stop;
    1227    56100485 :                 } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
    1228           0 :                         if (ret == MAL_SUCCEED)
    1229           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
    1230           0 :                         stkpc = mb->stop;
    1231             :                 }
    1232             :         }
    1233             : 
    1234             :         /* if we could not find the exception variable, cascade a new one */
    1235             :         /* don't add 'exception not caught' extra message for MAL sequences besides main function calls */
    1236    12151994 :         if (exceptionVar >= 0 && (ret == MAL_SUCCEED || !pcicaller)) {
    1237           1 :                 char nme[256];
    1238           1 :                 snprintf(nme, 256, "%s.%s[%d]", getModuleId(getInstrPtr(mb, 0)),
    1239           1 :                                  getFunctionId(getInstrPtr(mb, 0)), stkpc);
    1240           1 :                 if (ret != MAL_SUCCEED) {
    1241           0 :                         str new, n;
    1242           0 :                         n = createException(MAL, nme, "exception not caught");
    1243           0 :                         if (n) {
    1244           0 :                                 new = GDKzalloc(strlen(ret) + strlen(n) + 16);
    1245           0 :                                 if (new) {
    1246           0 :                                         strcpy(new, ret);
    1247           0 :                                         if (new[strlen(new) - 1] != '\n')
    1248           0 :                                                 strcat(new, "\n");
    1249           0 :                                         strcat(new, "!");
    1250           0 :                                         strcat(new, n);
    1251           0 :                                         freeException(n);
    1252           0 :                                         freeException(ret);
    1253           0 :                                         ret = new;
    1254             :                                 } else {
    1255           0 :                                         freeException(ret);
    1256           0 :                                         ret = n;
    1257             :                                 }
    1258             :                         }
    1259             :                 } else {
    1260           1 :                         ret = createException(MAL, nme, "Exception not caught");
    1261             :                 }
    1262             :         }
    1263    12151994 :         if (startedProfileQueue)
    1264      636603 :                 runtimeProfileFinish(cntxt, mb, stk);
    1265    12152643 :         if (backup != backups)
    1266      218591 :                 GDKfree(backup);
    1267    12145400 :         if (garbage != garbages)
    1268      220174 :                 GDKfree(garbage);
    1269             :         return ret;
    1270             : }
    1271             : 
    1272             : 
    1273             : /*
    1274             :  * MAL API
    1275             :  * The linkage between MAL interpreter and compiled C-routines
    1276             :  * is kept as simple as possible.
    1277             :  * Basically we distinguish four kinds of calling conventions:
    1278             :  * CMDcall, FCNcall and PATcall.
    1279             :  * The FCNcall indicates calling a MAL procedure, which leads
    1280             :  * to a recursive call to the interpreter.
    1281             :  *
    1282             :  * CMDcall initiates calling a linked function, passing pointers
    1283             :  * to the parameters and result variable, i.e.  f(ptr a0,..., ptr aN)
    1284             :  * The function returns a MAL-SUCCEED upon success and a pointer
    1285             :  * to an exception string upon failure.
    1286             :  * Failure leads to raise-ing an exception in the interpreter loop,
    1287             :  * by either looking up the relevant exception message in the module
    1288             :  * administration or construction of a standard string.
    1289             :  *
    1290             :  * The PATcall initiates a call which contains the MAL context,
    1291             :  * i.e. f(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1292             :  * The mb provides access to the code definitions. It is primarilly
    1293             :  * used by routines intended to manipulate the code base itself, such
    1294             :  * as the optimizers. The Mal stack frame pointer provides access
    1295             :  * to the values maintained. The arguments passed are offsets
    1296             :  * into the stack frame rather than pointers to the actual value.
    1297             :  *
    1298             :  * BAT parameters require some care. Ideally, a BAT should not be kept
    1299             :  * around long. This would mean that each time we access a BAT it has to be
    1300             :  * pinned in memory and upon leaving the function, it is unpinned.
    1301             :  * This degrades performance significantly.
    1302             :  * After the parameters are fixed, we can safely free the destination
    1303             :  * variable and re-initialize it to nil.
    1304             :  *
    1305             :  */
    1306             : 
    1307             : /*
    1308             :  * The type dispatching table in getArgReference can be removed if we
    1309             :  * determine at compile time the address offset within a ValRecord.
    1310             :  * We leave this optimization for the future, it leads to about 10%
    1311             :  * improvement (100ms for 1M calls).
    1312             :  *
    1313             :  * Flow of control statements
    1314             :  * Each assignment (function call) may be part of the initialization
    1315             :  * of a barrier- block. In that case we have to test the
    1316             :  * outcome of the operation and possibly skip the block altogether.
    1317             :  * The latter is implemented as a linear scan for the corresponding
    1318             :  * labeled statemtent. This might be optimized later.
    1319             :  *
    1320             :  * You can skip to a catch block by searching for the corresponding 'lab'
    1321             :  * The return value should be set to pass the error automatically upon
    1322             :  * reaching end of function block.
    1323             :  */
    1324             : 
    1325             : /*
    1326             :  * Each time we enter a barrier block, we could keep its position in the
    1327             :  * interpreter stack frame. It forms the starting point to issue a redo.
    1328             :  * Unfortunately, this does not easily work in the presence of optimizers, which
    1329             :  * may change the order/block structure. Therefore, we simple have to search
    1330             :  * the beginning or ensure that during chkProgram the barrier/redo/leave/catch
    1331             :  * jumps are re-established.
    1332             :  *
    1333             :  * Exception handling
    1334             :  * Calling a built-in or user-defined routine may lead to an error or a
    1335             :  * cached status message to be dealt with in MAL.
    1336             :  * To improve error handling in MAL, an exception handling
    1337             :  * scheme based on @sc{catch}-@sc{exit} blocks. The @sc{catch}
    1338             :  * statement identifies a (string-valued) variable, which carries the
    1339             :  * exception message from
    1340             :  * the originally failed routine or @sc{raise} exception assignment.
    1341             :  * During normal processing @sc{catch}-@sc{exit} blocks are simply skipped.
    1342             :  * Upon receiving an exception status from a function call, we set the
    1343             :  * exception variable and skip to the first associated @sc{catch}-@sc{exit}
    1344             :  * block.
    1345             :  * MAL interpretation then continues until it reaches the end of the block.
    1346             :  * If no exception variable was defined, we should abandon the function
    1347             :  * alltogether searching for a catch block at a higher layer.
    1348             :  *
    1349             :  * For the time being we have ignored cascaded/stacked exceptions.
    1350             :  * The policy is to pass the first recognized exception to a context
    1351             :  * in which it can be handled.
    1352             :  *
    1353             :  * Exceptions raised within a linked-in function requires some care.
    1354             :  * First, the called procedure does not know anything about the MAL
    1355             :  * interpreter context. Thus, we need to return all relevant information
    1356             :  * upon leaving the linked library routine.
    1357             :  *
    1358             :  * Second, exceptional cases can be handled deeply in the recursion, where they
    1359             :  * may also be handled, i.e. by issueing an GDKerror message. The upper layers
    1360             :  * merely receive a negative integer value to indicate occurrence of an
    1361             :  * error somewhere in the calling sequence.
    1362             :  * We then have to also look into GDKerrbuf to see if there was
    1363             :  * an error raised deeply inside the system.
    1364             :  *
    1365             :  * The policy is to require all C-functions to return a string-pointer.
    1366             :  * Upon a successful call, it is a NULL string. Otherwise it contains an
    1367             :  * encoding of the exceptional state encountered. This message
    1368             :  * starts with the exception identifer, followed by contextual details.
    1369             :  */
    1370             : 
    1371             : /*
    1372             :  * Garbage collection
    1373             :  * Garbage collection is relatively straightforward, because most values are
    1374             :  * retained on the stackframe of an interpreter call. However, two storage
    1375             :  * types and possibly user-defined type garbage collector definitions
    1376             :  * require attention: BATs and strings.
    1377             :  *
    1378             :  * A key issue is to deal with temporary BATs in an efficient way.
    1379             :  * References to bats in the buffer pool may cause dangling references
    1380             :  * at the language level. This appears as soons as your share
    1381             :  * a reference and delete the BAT from one angle. If not careful, the
    1382             :  * dangling pointer may subsequently be associated with another BAT
    1383             :  *
    1384             :  * All string values are private to the VALrecord, which means they
    1385             :  * have to be freed explicitly before a MAL function returns.
    1386             :  * The first step is to always safe the destination variable
    1387             :  * before a function call is made.
    1388             :  */
    1389             : void
    1390   164032384 : garbageElement(Client cntxt, ValPtr v)
    1391             : {
    1392   164032384 :         (void) cntxt;
    1393   164032384 :         if (v->bat) {
    1394             :                 /*
    1395             :                  * All operations are responsible to properly set the
    1396             :                  * reference count of the BATs being produced or destroyed.
    1397             :                  * The libraries should not leave the
    1398             :                  * physical reference count being set. This is only
    1399             :                  * allowed during the execution of a GDK operation.
    1400             :                  * All references should be logical.
    1401             :                  */
    1402    20145145 :                 bat bid = v->val.bval;
    1403             :                 /* printf("garbage collecting: %d lrefs=%d refs=%d\n",
    1404             :                    bid, BBP_lrefs(bid),BBP_refs(bid)); */
    1405    20145145 :                 v->val.bval = bat_nil;
    1406    20145145 :                 v->bat = false;
    1407    20145145 :                 if (is_bat_nil(bid))
    1408             :                         return;
    1409      316624 :                 BBPcold(bid);
    1410      316622 :                 BBPrelease(bid);
    1411   143887239 :         } else if (ATOMstorage(v->vtype) == TYPE_str) {
    1412    36807077 :                 GDKfree(v->val.sval);
    1413    36807400 :                 v->val.sval = NULL;
    1414    36807400 :                 v->len = 0;
    1415   107080162 :         } else if (0 < v->vtype && v->vtype < MAXATOMS && ATOMextern(v->vtype)) {
    1416        2640 :                 GDKfree(v->val.pval);
    1417        2640 :                 v->val.pval = 0;
    1418        2640 :                 v->len = 0;
    1419             :         }
    1420             : }
    1421             : 
    1422             : /*
    1423             :  * Before we return from the interpreter, we should free all
    1424             :  * dynamically allocated objects and adjust the BAT reference counts.
    1425             :  * Early experience shows that for small stack frames the overhead
    1426             :  * is about 200 ms for a 1M function call loop (tst400e). This means that
    1427             :  * for the time being we do not introduce more complex garbage
    1428             :  * administration code.
    1429             :  *
    1430             :  * Also note that for top-level stack frames (no environment available),
    1431             :  * we should retain the value stack because it acts as a global variables.
    1432             :  * This situation is indicated by the 'global' in the stack frame.
    1433             :  * Upon termination of the session, the stack should be cleared.
    1434             :  * Beware that variables may be know polymorphic, their actual
    1435             :  * type should be saved for variables that recide on a global
    1436             :  * stack frame.
    1437             :  */
    1438             : void
    1439      738816 : garbageCollector(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int flag)
    1440             : {
    1441      738816 :         assert(mb->vtop <= mb->vsize);
    1442      738816 :         assert(stk->stktop <= stk->stksize);
    1443             :         (void) flag;
    1444             :         (void) mb;
    1445             :         (void) cntxt;
    1446   164743834 :         for (int k = 0; k < stk->stktop; k++) {
    1447             :                 //  if (isVarCleanup(mb, k) ){
    1448   164005035 :                 ValPtr v = &stk->stk[k];
    1449   164005035 :                 garbageElement(cntxt, v);
    1450   164005018 :                 *v = (ValRecord) {
    1451             :                         .vtype = TYPE_int,
    1452             :                         .val.ival = int_nil,
    1453             :                         .bat = false,
    1454             :                 };
    1455             :                 //  }
    1456             :         }
    1457      738799 : }

Generated by: LCOV version 1.14