LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_interpreter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 436 669 65.2 %
Date: 2024-11-13 19:37:10 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    37982475 : 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    37982475 :         return (ptr) &stk->stk[pci->argv[k]].val;
      43             : }
      44             : 
      45             : static str
      46    35616442 : malCommandCall(MalStkPtr stk, InstrPtr pci)
      47             : {
      48    35616442 :         str ret = MAL_SUCCEED;
      49             : 
      50    35616442 :         switch (pci->argc) {
      51           0 :         case 0:
      52           0 :                 ret = (*(str (*) (void)) pci->fcn)();
      53           0 :                 break;
      54     1010323 :         case 1:
      55     1010323 :                 ret = (*(str (*) (void *)) pci->fcn)(
      56             :                         getArgReference(stk, pci, 0));
      57     1010323 :                 break;
      58      198463 :         case 2:
      59      198463 :                 ret = (*(str (*) (void *, void *)) pci->fcn)(
      60             :                         getArgReference(stk, pci, 0),
      61             :                         getArgReference(stk, pci, 1));
      62      198463 :                 break;
      63    31768834 :         case 3:
      64    31768834 :                 ret = (*(str (*) (void *, void *, void *)) pci->fcn)(
      65             :                         getArgReference(stk, pci, 0),
      66             :                         getArgReference(stk, pci, 1),
      67             :                         getArgReference(stk, pci, 2));
      68    31768834 :                 break;
      69      686668 :         case 4:
      70      686668 :                 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      686668 :                 break;
      76     1115504 :         case 5:
      77     1115504 :                 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     1115504 :                 break;
      84        4404 :         case 6:
      85        4404 :                 ret = (*(str (*) (void *, void *, void *, void *, void *,
      86        4404 :                                                   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        4404 :                 break;
      94      179002 :         case 7:
      95      179002 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
      96      179002 :                                                    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      179002 :                 break;
     105      630353 :         case 8:
     106      630353 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     107      630353 :                                                    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      630353 :                 break;
     117       22679 :         case 9:
     118       22679 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     119       22679 :                                                    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       22679 :                 break;
     130          31 :         case 10:
     131          31 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     132          31 :                                                    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          31 :                 break;
     144          63 :         case 11:
     145          63 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     146          63 :                                                    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          63 :                 break;
     159         118 :         case 12:
     160         118 :                 ret = (* (str (*) (void *, void *, void *, void *, void *, void *,
     161             :                                                    void *, void *, void *, void *, void *,
     162         118 :                                                    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         118 :                 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    12051917 : isNotUsedIn(InstrPtr p, int start, int a)
     284             : {
     285    29559075 :         for (int k = start; k < p->argc; k++)
     286    17517596 :                 if (getArg(p, k) == a)
     287             :                         return false;
     288             :         return true;
     289             : }
     290             : 
     291             : MalStkPtr
     292      661373 : prepareMALstack(MalBlkPtr mb, int size)
     293             : {
     294      661373 :         MalStkPtr stk = NULL;
     295      661373 :         int res = 1;
     296      661373 :         ValPtr lhs, rhs;
     297             : 
     298      661373 :         stk = newGlobalStack(size);
     299      661453 :         if (!stk)
     300             :                 return NULL;
     301      661453 :         stk->stktop = mb->vtop;
     302      661453 :         stk->blk = mb;
     303      661453 :         stk->memory = 0;
     304   120581054 :         initStack(0, res);
     305      661430 :         if (!res) {
     306           0 :                 freeStack(stk);
     307           0 :                 return NULL;
     308             :         }
     309             :         return stk;
     310             : }
     311             : 
     312             : str
     313      569447 : runMAL(Client cntxt, MalBlkPtr mb, MalBlkPtr mbcaller, MalStkPtr env)
     314             : {
     315      569447 :         MalStkPtr stk = NULL;
     316      569447 :         ValPtr lhs, rhs;
     317      569447 :         str ret;
     318      569447 :         (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      569447 :         cntxt->lastcmd = time(0);
     335      569447 :         ATOMIC_SET(&cntxt->lastprint, GDKusec());
     336      569457 :         if (env != NULL) {
     337        9945 :                 int res = 1;
     338        9945 :                 stk = env;
     339        9945 :                 if (mb != stk->blk)
     340           0 :                         throw(MAL, "mal.interpreter", "misalignment of symbols");
     341        9945 :                 if (mb->vtop > stk->stksize)
     342           0 :                         throw(MAL, "mal.interpreter", "stack too small");
     343       26094 :                 initStack(env->stkbot, res);
     344        9945 :                 if (!res)
     345           0 :                         throw(MAL, "mal.interpreter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     346             :         } else {
     347      559512 :                 stk = prepareMALstack(mb, mb->vsize);
     348      559489 :                 if (stk == 0)
     349           0 :                         throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     350      559489 :                 stk->blk = mb;
     351             :                 /*safeguardStack */
     352      559489 :                 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      569434 :         ret = runMALsequence(cntxt, mb, 1, 0, stk, env, 0);
     369             : 
     370      569457 :         if (!stk->keepAlive && garbageControl(getInstrPtr(mb, 0)))
     371      559512 :                 garbageCollector(cntxt, mb, stk, env != stk);
     372      569440 :         if (stk && stk != env)
     373      559492 :                 freeStack(stk);
     374      569460 :         if (ret == MAL_SUCCEED) {
     375      551753 :                 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      104836 : reenterMAL(Client cntxt, MalBlkPtr mb, int startpc, int stoppc, MalStkPtr stk)
     398             : {
     399      104836 :         str ret;
     400      104836 :         int keepAlive;
     401             : 
     402      104836 :         if (stk == NULL)
     403           0 :                 throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     404      104836 :         keepAlive = stk->keepAlive;
     405      104836 :         ret = runMALsequence(cntxt, mb, startpc, stoppc, stk, 0, 0);
     406             : 
     407      104830 :         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    14419390 : runMALsequence(Client cntxt, MalBlkPtr mb, int startpc,
     492             :                            int stoppc, MalStkPtr stk, MalStkPtr env, InstrPtr pcicaller)
     493             : {
     494    14419390 :         ValPtr lhs, rhs, v;
     495    14419390 :         InstrPtr pci = 0;
     496    14419390 :         int exceptionVar;
     497    14419390 :         str ret = MAL_SUCCEED, localGDKerrbuf = GDKerrbuf;
     498    14420840 :         ValRecord backups[16];
     499    14420840 :         ValPtr backup;
     500    14420840 :         int garbages[16], *garbage;
     501    14420840 :         int stkpc = 0;
     502    14420840 :         RuntimeProfileRecord runtimeProfile, runtimeProfileFunction;
     503    14420840 :         lng lastcheck = 0;
     504    14420840 :         bool startedProfileQueue = false;
     505             : #define CHECKINTERVAL 1000              /* how often do we check for client disconnect */
     506    14420840 :         runtimeProfile.ticks = runtimeProfileFunction.ticks = 0;
     507             : 
     508    14420840 :         if (stk == NULL)
     509           0 :                 throw(MAL, "mal.interpreter", MAL_STACK_FAIL);
     510             : 
     511             :         /* prepare extended backup and garbage structures */
     512    14420840 :         if (startpc + 1 == stoppc) {
     513    13777090 :                 pci = getInstrPtr(mb, startpc);
     514    13777090 :                 if (pci->argc > 16) {
     515      129787 :                         backup = GDKmalloc(pci->argc * sizeof(ValRecord));
     516      129588 :                         garbage = (int *) GDKzalloc(pci->argc * sizeof(int));
     517      129609 :                         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    13647303 :                         backup = backups;
     524    13647303 :                         garbage = garbages;
     525    13647303 :                         memset(garbages, 0, sizeof(garbages));
     526             :                 }
     527      643750 :         } else if (mb->maxarg > 16) {
     528      113352 :                 backup = GDKmalloc(mb->maxarg * sizeof(ValRecord));
     529      113352 :                 garbage = (int *) GDKzalloc(mb->maxarg * sizeof(int));
     530      113352 :                 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      530398 :                 backup = backups;
     537      530398 :                 garbage = garbages;
     538      530398 :                 memset(garbages, 0, sizeof(garbages));
     539             :         }
     540             : 
     541             :         /* also produce event record for start of function */
     542    14420662 :         if (startpc == 1 && startpc < mb->stop) {
     543      643748 :                 startedProfileQueue = true;
     544      643748 :                 runtimeProfileInit(cntxt, mb, stk);
     545      643788 :                 runtimeProfileBegin(cntxt, mb, stk, getInstrPtr(mb, 0),
     546             :                                                         &runtimeProfileFunction);
     547      643790 :                 if (cntxt->sessiontimeout
     548      125884 :                         && 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    14420704 :         stkpc = startpc;
     560    14420704 :         exceptionVar = -1;
     561             : 
     562    73352823 :         while (stkpc < mb->stop && stkpc != stoppc) {
     563             :                 // incomplete block being executed, requires at least signature and end statement
     564    59075750 :                 MT_thread_setalgorithm(NULL);
     565    58990078 :                 pci = getInstrPtr(mb, stkpc);
     566    58990078 :                 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    58990077 :                 freeException(ret);
     575    58969894 :                 ret = MAL_SUCCEED;
     576             : 
     577    58969894 :                 if (stk->status) {
     578             :                         /* pause procedure from SYSMON */
     579           1 :                         if (stk->status == 'p') {
     580           0 :                                 while (stk->status == 'p')
     581           0 :                                         MT_sleep_ms(50);
     582           0 :                                 continue;
     583             :                         }
     584             :                         /* stop procedure from SYSMON */
     585           1 :                         if (stk->status == 'q') {
     586           1 :                                 stkpc = mb->stop;
     587           1 :                                 ret = createException(MAL, "mal.interpreter",
     588             :                                                                           "Query with tag " OIDFMT
     589             :                                                                           " received stop signal", mb->tag);
     590           1 :                                 break;
     591             :                         }
     592             :                 }
     593             :                 //Ensure we spread system resources over multiple users as well.
     594    58969893 :                 runtimeProfileBegin(cntxt, mb, stk, pci, &runtimeProfile);
     595    59002188 :                 if (runtimeProfile.ticks > lastcheck + CHECKINTERVAL) {
     596    14482398 :                         if (cntxt->fdin && TIMEOUT_TEST(&cntxt->qryctx)) {
     597           0 :                                 if (cntxt->qryctx.endtime != QRY_INTERRUPT && cntxt->qryctx.endtime != QRY_TIMEOUT)
     598           0 :                                         cntxt->mode = FINISHCLIENT;
     599           0 :                                 switch (cntxt->qryctx.endtime) {
     600           0 :                                 case QRY_TIMEOUT:
     601           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     602           0 :                                         break;
     603           0 :                                 case QRY_INTERRUPT:
     604           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
     605           0 :                                         break;
     606           0 :                                 default:
     607           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) "Client disconnected");
     608           0 :                                         cntxt->mode = FINISHCLIENT;
     609           0 :                                         break;
     610             :                                 }
     611             :                                 break;
     612             :                         }
     613    14416124 :                         lastcheck = runtimeProfile.ticks;
     614             :                 }
     615             : 
     616    58935914 :                 if (qptimeout > 0) {
     617           0 :                         lng t = GDKusec();
     618           0 :                         ATOMIC_BASE_TYPE lp = ATOMIC_GET(&cntxt->lastprint);
     619           0 :                         if ((lng) lp + qptimeout < t) {
     620             :                                 /* if still the same, replace lastprint with current
     621             :                                  * time and print the query */
     622           0 :                                 if (ATOMIC_CAS(&cntxt->lastprint, &lp, t)) {
     623           0 :                                         const char *q = cntxt->query ? cntxt->query : NULL;
     624           0 :                                         TRC_INFO(MAL_SERVER,
     625             :                                                          "%s: query already running " LLFMT "s: %.200s\n",
     626             :                                                          cntxt->mythread ? cntxt->mythread : "?",
     627             :                                                          (lng) (time(0) - cntxt->lastcmd), q ? q : "");
     628             :                                 }
     629             :                         }
     630             :                 }
     631             : 
     632             :                 /* The interpreter loop
     633             :                  * The interpreter is geared towards execution a MAL
     634             :                  * procedure together with all its descendant
     635             :                  * invocations. As such, it provides the MAL abstract
     636             :                  * machine processor.
     637             :                  *
     638             :                  * The value-stack frame of the surrounding scope is
     639             :                  * needed to resolve binding values.  Getting (putting) a
     640             :                  * value from (into) a surrounding scope should be guarded
     641             :                  * with the exclusive access lock.  This situation is
     642             :                  * encapsulated by a bind() function call, whose
     643             :                  * parameters contain the access mode required.
     644             :                  *
     645             :                  * The formal procedure arguments are assumed to always
     646             :                  * occupy the first elements in the value stack.
     647             :                  *
     648             :                  * Before we execute an instruction the variables to be
     649             :                  * garbage collected are identified. In the post-execution
     650             :                  * phase they are removed.
     651             :                  */
     652   118508718 :                 for (int i = 0; i < pci->retc; i++)
     653    59572804 :                         backup[i] = stk->stk[getArg(pci, i)];
     654             : 
     655    58935914 :                 if (garbageControl(pci)) {
     656   151380186 :                         for (int i = 0; i < pci->argc; i++) {
     657   119198327 :                                 int a = getArg(pci, i);
     658             : 
     659   119198327 :                                 if (stk->stk[a].bat && getEndScope(mb, a) == stkpc
     660    24103834 :                                         && isNotUsedIn(pci, i + 1, a))
     661    12043617 :                                         garbage[i] = a;
     662             :                                 else
     663   107154710 :                                         garbage[i] = -1;
     664             :                         }
     665             :                 }
     666             : 
     667    58935914 :                 switch (pci->token) {
     668     3538389 :                 case ASSIGNsymbol:
     669             :                         /* Assignment command
     670             :                          * The assignment statement copies values around on
     671             :                          * the stack frame, including multiple assignments.
     672             :                          *
     673             :                          * Pushing constants/initial values onto the stack is
     674             :                          * a separate operation.  It takes the constant value
     675             :                          * discovered at compile time and stored in the symbol
     676             :                          * table and moves it to the stackframe location. This
     677             :                          * activity is made part of the start-up procedure.
     678             :                          *
     679             :                          * The before after calls should be reconsidered here,
     680             :                          * because their. They seem superfluous and the way
     681             :                          * they are used will cause errors in multi-assignment
     682             :                          * statements.
     683             :                          */
     684     7030536 :                         for (int k = 0, i = pci->retc; k < pci->retc && i < pci->argc;
     685     3492147 :                                  i++, k++) {
     686     3492057 :                                 lhs = &stk->stk[pci->argv[k]];
     687     3492057 :                                 assert(lhs->bat == isaBatType(getArgType(mb, pci, k)));
     688     3492057 :                                 rhs = &stk->stk[pci->argv[i]];
     689     3492057 :                                 assert(rhs->bat == isaBatType(getArgType(mb, pci, i)));
     690     3492057 :                                 if (VALcopy(lhs, rhs) == NULL) {
     691           0 :                                         ret = createException(MAL, "mal.interpreter",
     692             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     693           0 :                                         break;
     694     3492147 :                                 } else if (lhs->bat && !is_bat_nil(lhs->val.bval))
     695        7607 :                                         BBPretain(lhs->val.bval);
     696             :                         }
     697             :                         break;
     698    19143706 :                 case PATcall:
     699    19143706 :                         if (pci->fcn == NULL) {
     700           0 :                                 ret = createException(MAL, "mal.interpreter",
     701             :                                                                           "address of pattern %s.%s missing",
     702             :                                                                           pci->modname, pci->fcnname);
     703             :                         } else {
     704    19143706 :                                 TRC_DEBUG(ALGO, "calling %s.%s\n",
     705             :                                                   pci->modname ? pci->modname : "<null>",
     706             :                                                   pci->fcnname ? pci->fcnname : "<null>");
     707    19143706 :                                 ret = (*(str (*) (Client, MalBlkPtr, MalStkPtr, InstrPtr)) pci->
     708             :                                            fcn) (cntxt, mb, stk, pci);
     709             : #ifndef NDEBUG
     710    19160347 :                                 if (ret == MAL_SUCCEED) {
     711             :                                         /* check that the types of actual results match
     712             :                                          * expected results */
     713    38975717 :                                         for (int i = 0; i < pci->retc; i++) {
     714    19830892 :                                                 int a = getArg(pci, i);
     715    19830892 :                                                 int t = getArgType(mb, pci, i);
     716             : 
     717    19830892 :                                                 if (isaBatType(t)) {
     718     6770383 :                                                         bat bid = stk->stk[a].val.bval;
     719     6770383 :                                                         BAT *_b;
     720     6770383 :                                                         t = getBatType(t);
     721     6770383 :                                                         assert(stk->stk[a].bat);
     722    19664497 :                                                         assert(is_bat_nil(bid) ||
     723             :                                                                    t == TYPE_any ||
     724             :                                                                    ((_b = BBP_desc(bid)) != NULL &&
     725             :                                                                         ATOMtype(_b->ttype) == ATOMtype(t)));
     726             :                                                 } else {
     727    13060509 :                                                         assert(t == stk->stk[a].vtype);
     728             :                                                 }
     729             :                                         }
     730             :                                 }
     731             : #endif
     732             :                         }
     733             :                         break;
     734    35621905 :                 case CMDcall:
     735    35621905 :                         TRC_DEBUG(ALGO, "calling %s.%s\n",
     736             :                                           pci->modname ? pci->modname : "<null>",
     737             :                                           pci->fcnname ? pci->fcnname : "<null>");
     738    35621905 :                         ret = malCommandCall(stk, pci);
     739             : #ifndef NDEBUG
     740    35618064 :                         if (ret == MAL_SUCCEED) {
     741             :                                 /* check that the types of actual results match
     742             :                                  * expected results */
     743    71820637 :                                 for (int i = 0; i < pci->retc; i++) {
     744    36192892 :                                         int a = getArg(pci, i);
     745    36192892 :                                         int t = getArgType(mb, pci, i);
     746             : 
     747    36192892 :                                         if (isaBatType(t)) {
     748             :                                                 //bat bid = stk->stk[a].val.bval;
     749    20480291 :                                                 t = getBatType(t);
     750    20480291 :                                                 assert(stk->stk[a].bat);
     751             :                                                 //assert( !is_bat_nil(bid));
     752    20480291 :                                                 assert(t != TYPE_any);
     753             :                                                 //assert( ATOMtype(BBP_desc(bid)->ttype) == ATOMtype(t));
     754             :                                         } else {
     755    15712601 :                                                 assert(t == stk->stk[a].vtype);
     756             :                                         }
     757             :                                 }
     758             :                         }
     759             : #endif
     760             :                         break;
     761       74282 :                 case FCNcall: {
     762             :                         /*
     763             :                          * MAL function calls are relatively expensive,
     764             :                          * because they have to assemble a new stack frame and
     765             :                          * do housekeeping, such as garbagecollection of all
     766             :                          * non-returned values.
     767             :                          */
     768       74282 :                         MalStkPtr nstk;
     769       74282 :                         InstrPtr q;
     770       74282 :                         int ii, arg;
     771             : 
     772       74282 :                         nstk = prepareMALstack(pci->blk, pci->blk->vsize);
     773       74282 :                         if (nstk == 0) {
     774           0 :                                 ret = createException(MAL, "mal.interpreter", MAL_STACK_FAIL);
     775           0 :                                 break;
     776             :                         }
     777       74282 :                         nstk->pcup = stkpc;
     778             : 
     779             :                         /*safeguardStack */
     780       74282 :                         nstk->stkdepth = nstk->stksize + stk->stkdepth;
     781       74282 :                         nstk->calldepth = stk->calldepth + 1;
     782       74282 :                         nstk->up = stk;
     783       74282 :                         if (nstk->calldepth > 256) {
     784           1 :                                 ret = createException(MAL, "mal.interpreter",
     785             :                                                                           MAL_CALLDEPTH_FAIL);
     786           1 :                                 GDKfree(nstk);
     787           1 :                                 break;
     788             :                         }
     789       74281 :                         if ((unsigned) nstk->stkdepth >
     790       46308 :                                 THREAD_STACK_SIZE / sizeof(mb->var[0]) / 4 && THRhighwater()) {
     791             :                                 /* we are running low on stack space */
     792           0 :                                 ret = createException(MAL, "mal.interpreter", MAL_STACK_FAIL);
     793           0 :                                 GDKfree(nstk);
     794           0 :                                 break;
     795             :                         }
     796             : 
     797             :                         /* copy arguments onto destination stack */
     798       74281 :                         q = getInstrPtr(pci->blk, 0);
     799       74281 :                         arg = q->retc;
     800      380892 :                         for (ii = pci->retc; ii < pci->argc; ii++, arg++) {
     801      306610 :                                 lhs = &nstk->stk[q->argv[arg]];
     802      306610 :                                 rhs = &stk->stk[pci->argv[ii]];
     803      306610 :                                 if (VALcopy(lhs, rhs) == NULL) {
     804           0 :                                         GDKfree(nstk);
     805           0 :                                         ret = createException(MAL, "mal.interpreter",
     806             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     807           0 :                                         break;
     808      306611 :                                 } else if (lhs->bat)
     809          18 :                                         BBPretain(lhs->val.bval);
     810             :                         }
     811       74282 :                         if (ret == MAL_SUCCEED && ii == pci->argc) {
     812       74283 :                                 ret = runMALsequence(cntxt, pci->blk, 1, pci->blk->stop, nstk,
     813             :                                                                          stk, pci);
     814       74283 :                                 garbageCollector(cntxt, pci->blk, nstk, 0);
     815       74283 :                                 arg = q->retc;
     816      380894 :                                 for (ii = pci->retc; ii < pci->argc; ii++, arg++) {
     817      306611 :                                         lhs = &nstk->stk[q->argv[arg]];
     818      306611 :                                         if (lhs->bat)
     819           0 :                                                 BBPrelease(lhs->val.bval);
     820             :                                 }
     821       74283 :                                 GDKfree(nstk);
     822             :                         }
     823             :                         break;
     824             :                 }
     825             :                 case REMsymbol:
     826             :                         break;
     827      557534 :                 case ENDsymbol:
     828      557534 :                         runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
     829      557490 :                         runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb, 0),
     830             :                                                            &runtimeProfileFunction);
     831      557439 :                         if (pcicaller && garbageControl(getInstrPtr(mb, 0)))
     832        5998 :                                 garbageCollector(cntxt, mb, stk, TRUE);
     833      557439 :                         if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
     834           0 :                                 freeException(ret);     /* overrule exception */
     835           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     836           0 :                                 break;
     837      557439 :                         } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
     838           0 :                                 freeException(ret);     /* overrule exception */
     839           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
     840           0 :                                 break;
     841             :                         }
     842      557439 :                         stkpc = mb->stop;    // force end of loop
     843      557439 :                         continue;
     844           0 :                 default: {
     845           0 :                         str w;
     846           0 :                         if (pci->token < 0) {
     847             :                                 /* temporary NOOP instruction */
     848             :                                 break;
     849             :                         }
     850           0 :                         w = instruction2str(mb, 0, pci, FALSE);
     851           0 :                         if (w) {
     852           0 :                                 ret = createException(MAL, "interpreter", "unknown operation:%s",
     853             :                                                                           w);
     854           0 :                                 GDKfree(w);
     855             :                         } else {
     856           0 :                                 ret = createException(MAL, "interpreter",
     857             :                                                                           "failed instruction2str");
     858             :                         }
     859             :                         // runtimeProfileBegin already sets the time in the instruction
     860           0 :                         if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
     861           0 :                                 freeException(ret);     /* overrule exception */
     862           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     863           0 :                                 break;
     864           0 :                         } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
     865           0 :                                 freeException(ret);     /* overrule exception */
     866           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
     867           0 :                                 break;
     868             :                         }
     869             : 
     870           0 :                         stkpc = mb->stop;
     871           0 :                         continue;
     872             :                 }
     873             :                 }
     874             : 
     875             :                 /* monitoring information should reflect the input arguments,
     876             :                    which may be removed by garbage collection  */
     877             :                 /* BEWARE, the SQL engine or MAL function could zap the block, leaving garbage behind in pci */
     878             :                 /* this hack means we loose a closing event */
     879    58391271 :                 if (mb->stop <= 1)
     880           0 :                         continue;
     881    58391271 :                 runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
     882             :                 /* when we find a timeout situation, then the result is already known
     883             :                  * and assigned,  the backup version is not removed*/
     884    58357006 :                 if (ret == MAL_SUCCEED) {
     885   117927201 :                         for (int i = 0; i < pci->retc; i++) {
     886    59683861 :                                 lhs = &backup[i];
     887    59683861 :                                 if (lhs->bat) {
     888    27302501 :                                         BBPrelease(lhs->val.bval);
     889    32381360 :                                 } else if (ATOMextern(lhs->vtype) &&
     890     1855073 :                                         lhs->val.pval &&
     891      140596 :                                         lhs->val.pval != ATOMnilptr(lhs->vtype) &&
     892      140596 :                                         lhs->val.pval != stk->stk[getArg(pci, i)].val.pval)
     893      138208 :                                         GDKfree(lhs->val.pval);
     894             :                         }
     895    58243340 :                         if (ATOMIC_GET(&GDKdebug) & CHECKMASK && exceptionVar < 0) {
     896             :                                 BAT *b;
     897             : 
     898    54456160 :                                 for (int i = 0; i < pci->retc; i++) {
     899    27841871 :                                         if (garbage[i] == -1
     900    26129211 :                                                 && stk->stk[getArg(pci, i)].bat
     901    11532448 :                                                 && !is_bat_nil(stk->stk[getArg(pci, i)].val.bval)) {
     902    11487174 :                                                 assert(stk->stk[getArg(pci, i)].val.bval > 0);
     903    11487174 :                                                 b = BATdescriptor(stk->stk[getArg(pci, i)].val.bval);
     904    11538340 :                                                 if (b == NULL) {
     905           0 :                                                         if (ret == MAL_SUCCEED)
     906           0 :                                                                 ret = createException(MAL, "mal.propertyCheck",
     907             :                                                                                                           SQLSTATE(HY002)
     908             :                                                                                                           RUNTIME_OBJECT_MISSING);
     909           0 :                                                         continue;
     910             :                                                 }
     911    11538340 :                                                 BATassertProps(b);
     912    11530508 :                                                 BBPunfix(b->batCacheid);
     913             :                                         }
     914             :                                 }
     915             :                         }
     916             : 
     917             :                         /* general garbage collection */
     918    58331381 :                         if (ret == MAL_SUCCEED && garbageControl(pci)) {
     919   152269217 :                                 for (int i = 0; i < pci->argc; i++) {
     920   120108739 :                                         int a = getArg(pci, i);
     921             : 
     922   120108739 :                                         if (isaBatType(getArgType(mb, pci, i))) {
     923    67733559 :                                                 bat bid = stk->stk[a].val.bval;
     924             : 
     925    67733559 :                                                 if (garbage[i] >= 0) {
     926    12037996 :                                                         bid = stk->stk[garbage[i]].val.bval;
     927    12037996 :                                                         if (!is_bat_nil(bid)) {
     928    11597621 :                                                                 stk->stk[garbage[i]].val.bval = bat_nil;
     929    11597621 :                                                                 BBPcold(bid);
     930    11578073 :                                                                 BBPrelease(bid);
     931             :                                                         }
     932             :                                                 }
     933             :                                         }
     934             :                                 }
     935             :                         }
     936             :                 }
     937             : 
     938             :                 /* Exception handling */
     939    58374677 :                 if (localGDKerrbuf && localGDKerrbuf[0]) {
     940           2 :                         if (ret == MAL_SUCCEED)
     941           2 :                                 ret = createException(MAL, "mal.interpreter", GDK_EXCEPTION);
     942             :                         // TODO take properly care of the GDK exception
     943           2 :                         localGDKerrbuf[0] = 0;
     944             :                 }
     945             : 
     946    58374677 :                 if (ret != MAL_SUCCEED) {
     947       19015 :                         str msg = 0;
     948             : 
     949             :                         /* Detect any exception received from the implementation. */
     950             :                         /* The first identifier is an optional exception name */
     951       19015 :                         if (strstr(ret, "!skip-to-end")) {
     952           0 :                                 freeException(ret);
     953           0 :                                 ret = MAL_SUCCEED;
     954           0 :                                 stkpc = mb->stop;
     955           0 :                                 continue;
     956             :                         }
     957             :                         /*
     958             :                          * Exceptions are caught based on their name, which is part of the
     959             :                          * exception message. The ANYexception variable catches all.
     960             :                          */
     961       19015 :                         exceptionVar = -1;
     962       19015 :                         msg = strchr(ret, ':');
     963       19015 :                         if (msg) {
     964       19015 :                                 exceptionVar = findVariableLength(mb, ret, (int) (msg - ret));
     965             :                         }
     966       19019 :                         if (exceptionVar == -1)
     967       19017 :                                 exceptionVar = findVariableLength(mb, "ANYexception", 12);
     968             : 
     969             :                         /* unknown exceptions lead to propagation */
     970       19016 :                         if (exceptionVar == -1) {
     971       19000 :                                 if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
     972          11 :                                         freeException(ret);     /* overrule exception */
     973          11 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
     974       18989 :                                 } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
     975           0 :                                         freeException(ret);     /* overrule exception */
     976           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
     977             :                                 }
     978       19000 :                                 stkpc = mb->stop;
     979       19000 :                                 continue;
     980             :                         }
     981             :                         /* assure correct variable type */
     982          18 :                         if (getVarType(mb, exceptionVar) == TYPE_str) {
     983             :                                 /* watch out for concurrent access */
     984          18 :                                 MT_lock_set(&mal_contextLock);
     985          18 :                                 v = &stk->stk[exceptionVar];
     986          18 :                                 if (v->val.sval)
     987           5 :                                         freeException(v->val.sval);  /* old exception */
     988          18 :                                 VALset(v, TYPE_str, ret);
     989          18 :                                 ret = MAL_SUCCEED;
     990          18 :                                 MT_lock_unset(&mal_contextLock);
     991             :                         } else {
     992           0 :                                 mnstr_printf(cntxt->fdout, "%s", ret);
     993           0 :                                 freeException(ret);
     994           0 :                                 ret = MAL_SUCCEED;
     995             :                         }
     996             :                         /* position yourself at the catch instruction for further decisions */
     997             :                         /* skipToCatch(exceptionVar,@2,@3) */
     998             :                         /* skip to catch block or end */
     999         201 :                         for (; stkpc < mb->stop; stkpc++) {
    1000         201 :                                 InstrPtr l = getInstrPtr(mb, stkpc);
    1001         201 :                                 if (l->barrier == CATCHsymbol) {
    1002             :                                         int j;
    1003          18 :                                         for (j = 0; j < l->retc; j++)
    1004          18 :                                                 if (getArg(l, j) == exceptionVar)
    1005             :                                                         break;
    1006           0 :                                                 else if (getArgName(mb, l, j) && strcmp(getArgName(mb, l, j), "ANYexception") == 0)
    1007             :                                                         break;
    1008          18 :                                         if (j < l->retc)
    1009             :                                                 break;
    1010             :                                 }
    1011             :                         }
    1012          18 :                         if (stkpc == mb->stop) {
    1013           0 :                                 if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
    1014           0 :                                         freeException(ret);     /* overrule exception */
    1015           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
    1016           0 :                                         stkpc = mb->stop;
    1017           0 :                                 } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
    1018           0 :                                         freeException(ret);     /* overrule exception */
    1019           0 :                                         ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
    1020           0 :                                         stkpc = mb->stop;
    1021             :                                 }
    1022           0 :                                 continue;
    1023             :                         }
    1024          18 :                         pci = getInstrPtr(mb, stkpc);
    1025             :                 }
    1026             : 
    1027             :                 /*
    1028             :                  * After the expression has been evaluated we should check for
    1029             :                  * a possible change in the control flow.
    1030             :                  */
    1031    58355680 :                 switch (pci->barrier) {
    1032     1373015 :                 case BARRIERsymbol:
    1033     1373015 :                         v = &stk->stk[getDestVar(pci)];
    1034             :                         /* skip to end of barrier, depends on the type */
    1035     1373015 :                         switch (v->vtype) {
    1036     1368781 :                         case TYPE_bit:
    1037     1368781 :                                 if (v->val.btval == FALSE || is_bit_nil(v->val.btval))
    1038     1320180 :                                         stkpc = pci->jump;
    1039             :                                 break;
    1040           0 :                         case TYPE_bte:
    1041           0 :                                 if (is_bte_nil(v->val.btval))
    1042           0 :                                         stkpc = pci->jump;
    1043             :                                 break;
    1044        4209 :                         case TYPE_oid:
    1045        4209 :                                 if (is_oid_nil(v->val.oval))
    1046        3967 :                                         stkpc = pci->jump;
    1047             :                                 break;
    1048           0 :                         case TYPE_sht:
    1049           0 :                                 if (is_sht_nil(v->val.shval))
    1050           0 :                                         stkpc = pci->jump;
    1051             :                                 break;
    1052           9 :                         case TYPE_int:
    1053           9 :                                 if (is_int_nil(v->val.ival))
    1054           0 :                                         stkpc = pci->jump;
    1055             :                                 break;
    1056          15 :                         case TYPE_lng:
    1057          15 :                                 if (is_lng_nil(v->val.lval))
    1058           0 :                                         stkpc = pci->jump;
    1059             :                                 break;
    1060             : #ifdef HAVE_HGE
    1061           0 :                         case TYPE_hge:
    1062           0 :                                 if (is_hge_nil(v->val.hval))
    1063           0 :                                         stkpc = pci->jump;
    1064             :                                 break;
    1065             : #endif
    1066           1 :                         case TYPE_flt:
    1067           1 :                                 if (is_flt_nil(v->val.fval))
    1068           0 :                                         stkpc = pci->jump;
    1069             :                                 break;
    1070           0 :                         case TYPE_dbl:
    1071           0 :                                 if (is_dbl_nil(v->val.dval))
    1072           0 :                                         stkpc = pci->jump;
    1073             :                                 break;
    1074           0 :                         case TYPE_str:
    1075           0 :                                 if (strNil(v->val.sval))
    1076           0 :                                         stkpc = pci->jump;
    1077             :                                 break;
    1078           0 :                         default: {
    1079           0 :                                 char name[IDLENGTH] = { 0 };
    1080           0 :                                 ret = createException(MAL, "mal.interpreter",
    1081             :                                                                           "%s: Unknown barrier type", getVarNameIntoBuffer(mb,
    1082             :                                                                                                                                                          getDestVar
    1083             :                                                                                                                                                          (pci), name));
    1084             :                                          }
    1085             :                         }
    1086     1373015 :                         stkpc++;
    1087     1373015 :                         break;
    1088    14255754 :                 case LEAVEsymbol:
    1089             :                 case REDOsymbol:
    1090    14255754 :                         v = &stk->stk[getDestVar(pci)];
    1091             :                         /* skip to end of barrier, depending on the type */
    1092    14255754 :                         switch (v->vtype) {
    1093         863 :                         case TYPE_bit:
    1094         863 :                                 if (v->val.btval == TRUE)
    1095         445 :                                         stkpc = pci->jump;
    1096             :                                 else
    1097         418 :                                         stkpc++;
    1098             :                                 break;
    1099           0 :                         case TYPE_str:
    1100           0 :                                 if (!strNil(v->val.sval))
    1101           0 :                                         stkpc = pci->jump;
    1102             :                                 else
    1103           0 :                                         stkpc++;
    1104             :                                 break;
    1105       44517 :                         case TYPE_oid:
    1106       44517 :                                 if (!is_oid_nil(v->val.oval))
    1107       44281 :                                         stkpc = pci->jump;
    1108             :                                 else
    1109         236 :                                         stkpc++;
    1110             :                                 break;
    1111           0 :                         case TYPE_sht:
    1112           0 :                                 if (!is_sht_nil(v->val.shval))
    1113           0 :                                         stkpc = pci->jump;
    1114             :                                 else
    1115           0 :                                         stkpc++;
    1116             :                                 break;
    1117         119 :                         case TYPE_int:
    1118         119 :                                 if (!is_int_nil(v->val.ival))
    1119         114 :                                         stkpc = pci->jump;
    1120             :                                 else
    1121           5 :                                         stkpc++;
    1122             :                                 break;
    1123           0 :                         case TYPE_bte:
    1124           0 :                                 if (!is_bte_nil(v->val.btval))
    1125           0 :                                         stkpc = pci->jump;
    1126             :                                 else
    1127           0 :                                         stkpc++;
    1128             :                                 break;
    1129    14210253 :                         case TYPE_lng:
    1130    14210253 :                                 if (!is_lng_nil(v->val.lval))
    1131    14210238 :                                         stkpc = pci->jump;
    1132             :                                 else
    1133          15 :                                         stkpc++;
    1134             :                                 break;
    1135             : #ifdef HAVE_HGE
    1136           0 :                         case TYPE_hge:
    1137           0 :                                 if (!is_hge_nil(v->val.hval))
    1138           0 :                                         stkpc = pci->jump;
    1139             :                                 else
    1140           0 :                                         stkpc++;
    1141             :                                 break;
    1142             : #endif
    1143           2 :                         case TYPE_flt:
    1144           2 :                                 if (!is_flt_nil(v->val.fval))
    1145           1 :                                         stkpc = pci->jump;
    1146             :                                 else
    1147           1 :                                         stkpc++;
    1148             :                                 break;
    1149           0 :                         case TYPE_dbl:
    1150           0 :                                 if (!is_dbl_nil(v->val.dval))
    1151           0 :                                         stkpc = pci->jump;
    1152             :                                 else
    1153           0 :                                         stkpc++;
    1154             :                                 break;
    1155             :                         default:
    1156             :                                 break;
    1157             :                         }
    1158             :                         break;
    1159          41 :                 case CATCHsymbol:
    1160             :                         /* catch blocks are skipped unless
    1161             :                            searched for explicitly */
    1162          41 :                         if (exceptionVar < 0) {
    1163          20 :                                 stkpc = pci->jump;
    1164          20 :                                 break;
    1165             :                         }
    1166          21 :                         exceptionVar = -1;
    1167          21 :                         stkpc++;
    1168          21 :                         break;
    1169       48759 :                 case EXITsymbol:
    1170       48759 :                         if (getDestVar(pci) == exceptionVar)
    1171           0 :                                 exceptionVar = -1;
    1172       48759 :                         stkpc++;
    1173       48759 :                         break;
    1174          17 :                 case RAISEsymbol:
    1175          17 :                         exceptionVar = getDestVar(pci);
    1176             :                         //freeException(ret);
    1177          17 :                         ret = MAL_SUCCEED;
    1178          17 :                         if (getVarType(mb, getDestVar(pci)) == TYPE_str) {
    1179          15 :                                 char nme[256];
    1180          15 :                                 snprintf(nme, 256, "%s.%s[%d]", getModuleId(getInstrPtr(mb, 0)),
    1181          15 :                                                  getFunctionId(getInstrPtr(mb, 0)), stkpc);
    1182          15 :                                 ret = createException(MAL, nme, "%s",
    1183          15 :                                                                           stk->stk[getDestVar(pci)].val.sval);
    1184             :                         }
    1185             :                         /* skipToCatch(exceptionVar, @2, stk) */
    1186             :                         /* skip to catch block or end */
    1187         396 :                         for (; stkpc < mb->stop; stkpc++) {
    1188         382 :                                 InstrPtr l = getInstrPtr(mb, stkpc);
    1189         382 :                                 if (l->barrier == CATCHsymbol) {
    1190             :                                         int j;
    1191           3 :                                         for (j = 0; j < l->retc; j++)
    1192           3 :                                                 if (getArg(l, j) == exceptionVar)
    1193             :                                                         break;
    1194           0 :                                                 else if (getArgName(mb, l, j) && strcmp(getArgName(mb, l, j), "ANYexception") == 0)
    1195             :                                                         break;
    1196           3 :                                         if (j < l->retc)
    1197             :                                                 break;
    1198             :                                 }
    1199             :                         }
    1200          17 :                         if (stkpc == mb->stop) {
    1201          14 :                                 runtimeProfileExit(cntxt, mb, stk, pci, &runtimeProfile);
    1202          14 :                                 runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb, 0),
    1203             :                                                                    &runtimeProfileFunction);
    1204          14 :                                 break;
    1205             :                         }
    1206             :                         break;
    1207       68035 :                 case RETURNsymbol:
    1208             :                         /* a fake multi-assignment */
    1209       68035 :                         if (env != NULL && pcicaller != NULL) {
    1210             :                                 InstrPtr pp = pci;
    1211      138536 :                                 pci = pcicaller;
    1212      138536 :                                 for (int i = 0; i < pci->retc; i++) {
    1213       70503 :                                         rhs = &stk->stk[pp->argv[i]];
    1214       70503 :                                         lhs = &env->stk[pci->argv[i]];
    1215       70503 :                                         if (VALcopy(lhs, rhs) == NULL) {
    1216           0 :                                                 ret = createException(MAL, "mal.interpreter",
    1217             :                                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1218           0 :                                                 break;
    1219       70503 :                                         } else if (lhs->bat)
    1220        2931 :                                                 BBPretain(lhs->val.bval);
    1221             :                                 }
    1222       68033 :                                 if (garbageControl(getInstrPtr(mb, 0)))
    1223       67994 :                                         garbageCollector(cntxt, mb, stk, TRUE);
    1224             :                                 /* reset the clock */
    1225       68033 :                                 runtimeProfileExit(cntxt, mb, stk, pp, &runtimeProfile);
    1226       68033 :                                 runtimeProfileExit(cntxt, mb, stk, getInstrPtr(mb, 0),
    1227             :                                                                    &runtimeProfileFunction);
    1228             :                         }
    1229       68035 :                         stkpc = mb->stop;
    1230       68035 :                         continue;
    1231    42610059 :                 default:
    1232    42610059 :                         stkpc++;
    1233             :                 }
    1234    58287645 :                 if (cntxt->qryctx.endtime == QRY_TIMEOUT) {
    1235           0 :                         if (ret == MAL_SUCCEED)
    1236           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_TIMEOUT);
    1237           0 :                         stkpc = mb->stop;
    1238    58287645 :                 } else if (cntxt->qryctx.endtime == QRY_INTERRUPT) {
    1239           0 :                         if (ret == MAL_SUCCEED)
    1240           0 :                                 ret = createException(MAL, "mal.interpreter", SQLSTATE(HYT00) RUNTIME_QRY_INTERRUPT);
    1241           0 :                         stkpc = mb->stop;
    1242             :                 }
    1243             :         }
    1244             : 
    1245             :         /* if we could not find the exception variable, cascade a new one */
    1246             :         /* don't add 'exception not caught' extra message for MAL sequences besides main function calls */
    1247    14277075 :         if (exceptionVar >= 0 && (ret == MAL_SUCCEED || !pcicaller)) {
    1248           1 :                 char nme[256];
    1249           1 :                 snprintf(nme, 256, "%s.%s[%d]", getModuleId(getInstrPtr(mb, 0)),
    1250           1 :                                  getFunctionId(getInstrPtr(mb, 0)), stkpc);
    1251           1 :                 if (ret != MAL_SUCCEED) {
    1252           0 :                         str new, n;
    1253           0 :                         n = createException(MAL, nme, "exception not caught");
    1254           0 :                         if (n) {
    1255           0 :                                 new = GDKzalloc(strlen(ret) + strlen(n) + 16);
    1256           0 :                                 if (new) {
    1257           0 :                                         strcpy(new, ret);
    1258           0 :                                         if (new[strlen(new) - 1] != '\n')
    1259           0 :                                                 strcat(new, "\n");
    1260           0 :                                         strcat(new, "!");
    1261           0 :                                         strcat(new, n);
    1262           0 :                                         freeException(n);
    1263           0 :                                         freeException(ret);
    1264           0 :                                         ret = new;
    1265             :                                 } else {
    1266           0 :                                         freeException(ret);
    1267           0 :                                         ret = n;
    1268             :                                 }
    1269             :                         }
    1270             :                 } else {
    1271           1 :                         ret = createException(MAL, nme, "Exception not caught");
    1272             :                 }
    1273             :         }
    1274    14277075 :         if (startedProfileQueue)
    1275      643239 :                 runtimeProfileFinish(cntxt, mb, stk);
    1276    14277628 :         if (backup != backups)
    1277      242201 :                 GDKfree(backup);
    1278    14264057 :         if (garbage != garbages)
    1279      243205 :                 GDKfree(garbage);
    1280             :         return ret;
    1281             : }
    1282             : 
    1283             : 
    1284             : /*
    1285             :  * MAL API
    1286             :  * The linkage between MAL interpreter and compiled C-routines
    1287             :  * is kept as simple as possible.
    1288             :  * Basically we distinguish four kinds of calling conventions:
    1289             :  * CMDcall, FCNcall and PATcall.
    1290             :  * The FCNcall indicates calling a MAL procedure, which leads
    1291             :  * to a recursive call to the interpreter.
    1292             :  *
    1293             :  * CMDcall initiates calling a linked function, passing pointers
    1294             :  * to the parameters and result variable, i.e.  f(ptr a0,..., ptr aN)
    1295             :  * The function returns a MAL-SUCCEED upon success and a pointer
    1296             :  * to an exception string upon failure.
    1297             :  * Failure leads to raise-ing an exception in the interpreter loop,
    1298             :  * by either looking up the relevant exception message in the module
    1299             :  * administration or construction of a standard string.
    1300             :  *
    1301             :  * The PATcall initiates a call which contains the MAL context,
    1302             :  * i.e. f(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1303             :  * The mb provides access to the code definitions. It is primarilly
    1304             :  * used by routines intended to manipulate the code base itself, such
    1305             :  * as the optimizers. The Mal stack frame pointer provides access
    1306             :  * to the values maintained. The arguments passed are offsets
    1307             :  * into the stack frame rather than pointers to the actual value.
    1308             :  *
    1309             :  * BAT parameters require some care. Ideally, a BAT should not be kept
    1310             :  * around long. This would mean that each time we access a BAT it has to be
    1311             :  * pinned in memory and upon leaving the function, it is unpinned.
    1312             :  * This degrades performance significantly.
    1313             :  * After the parameters are fixed, we can safely free the destination
    1314             :  * variable and re-initialize it to nil.
    1315             :  *
    1316             :  */
    1317             : 
    1318             : /*
    1319             :  * The type dispatching table in getArgReference can be removed if we
    1320             :  * determine at compile time the address offset within a ValRecord.
    1321             :  * We leave this optimization for the future, it leads to about 10%
    1322             :  * improvement (100ms for 1M calls).
    1323             :  *
    1324             :  * Flow of control statements
    1325             :  * Each assignment (function call) may be part of the initialization
    1326             :  * of a barrier- block. In that case we have to test the
    1327             :  * outcome of the operation and possibly skip the block altogether.
    1328             :  * The latter is implemented as a linear scan for the corresponding
    1329             :  * labeled statemtent. This might be optimized later.
    1330             :  *
    1331             :  * You can skip to a catch block by searching for the corresponding 'lab'
    1332             :  * The return value should be set to pass the error automatically upon
    1333             :  * reaching end of function block.
    1334             :  */
    1335             : 
    1336             : /*
    1337             :  * Each time we enter a barrier block, we could keep its position in the
    1338             :  * interpreter stack frame. It forms the starting point to issue a redo.
    1339             :  * Unfortunately, this does not easily work in the presence of optimizers, which
    1340             :  * may change the order/block structure. Therefore, we simple have to search
    1341             :  * the beginning or ensure that during chkProgram the barrier/redo/leave/catch
    1342             :  * jumps are re-established.
    1343             :  *
    1344             :  * Exception handling
    1345             :  * Calling a built-in or user-defined routine may lead to an error or a
    1346             :  * cached status message to be dealt with in MAL.
    1347             :  * To improve error handling in MAL, an exception handling
    1348             :  * scheme based on @sc{catch}-@sc{exit} blocks. The @sc{catch}
    1349             :  * statement identifies a (string-valued) variable, which carries the
    1350             :  * exception message from
    1351             :  * the originally failed routine or @sc{raise} exception assignment.
    1352             :  * During normal processing @sc{catch}-@sc{exit} blocks are simply skipped.
    1353             :  * Upon receiving an exception status from a function call, we set the
    1354             :  * exception variable and skip to the first associated @sc{catch}-@sc{exit}
    1355             :  * block.
    1356             :  * MAL interpretation then continues until it reaches the end of the block.
    1357             :  * If no exception variable was defined, we should abandon the function
    1358             :  * altogether searching for a catch block at a higher layer.
    1359             :  *
    1360             :  * For the time being we have ignored cascaded/stacked exceptions.
    1361             :  * The policy is to pass the first recognized exception to a context
    1362             :  * in which it can be handled.
    1363             :  *
    1364             :  * Exceptions raised within a linked-in function requires some care.
    1365             :  * First, the called procedure does not know anything about the MAL
    1366             :  * interpreter context. Thus, we need to return all relevant information
    1367             :  * upon leaving the linked library routine.
    1368             :  *
    1369             :  * Second, exceptional cases can be handled deeply in the recursion, where they
    1370             :  * may also be handled, i.e. by issuing an GDKerror message. The upper layers
    1371             :  * merely receive a negative integer value to indicate occurrence of an
    1372             :  * error somewhere in the calling sequence.
    1373             :  * We then have to also look into GDKerrbuf to see if there was
    1374             :  * an error raised deeply inside the system.
    1375             :  *
    1376             :  * The policy is to require all C-functions to return a string-pointer.
    1377             :  * Upon a successful call, it is a NULL string. Otherwise it contains an
    1378             :  * encoding of the exceptional state encountered. This message
    1379             :  * starts with the exception identifier, followed by contextual details.
    1380             :  */
    1381             : 
    1382             : /*
    1383             :  * Garbage collection
    1384             :  * Garbage collection is relatively straightforward, because most values are
    1385             :  * retained on the stackframe of an interpreter call. However, two storage
    1386             :  * types and possibly user-defined type garbage collector definitions
    1387             :  * require attention: BATs and strings.
    1388             :  *
    1389             :  * A key issue is to deal with temporary BATs in an efficient way.
    1390             :  * References to bats in the buffer pool may cause dangling references
    1391             :  * at the language level. This appears as soons as your share
    1392             :  * a reference and delete the BAT from one angle. If not careful, the
    1393             :  * dangling pointer may subsequently be associated with another BAT
    1394             :  *
    1395             :  * All string values are private to the VALrecord, which means they
    1396             :  * have to be freed explicitly before a MAL function returns.
    1397             :  * The first step is to always safe the destination variable
    1398             :  * before a function call is made.
    1399             :  */
    1400             : void
    1401   168864442 : garbageElement(Client cntxt, ValPtr v)
    1402             : {
    1403   168864442 :         (void) cntxt;
    1404   168864442 :         if (v->bat) {
    1405             :                 /*
    1406             :                  * All operations are responsible to properly set the
    1407             :                  * reference count of the BATs being produced or destroyed.
    1408             :                  * The libraries should not leave the
    1409             :                  * physical reference count being set. This is only
    1410             :                  * allowed during the execution of a GDK operation.
    1411             :                  * All references should be logical.
    1412             :                  */
    1413    22625075 :                 bat bid = v->val.bval;
    1414             :                 /* printf("garbage collecting: %d lrefs=%d refs=%d\n",
    1415             :                    bid, BBP_lrefs(bid),BBP_refs(bid)); */
    1416    22625075 :                 v->val.bval = bat_nil;
    1417    22625075 :                 v->bat = false;
    1418    22625075 :                 if (is_bat_nil(bid))
    1419             :                         return;
    1420      371372 :                 BBPcold(bid);
    1421      371372 :                 BBPrelease(bid);
    1422   146239367 :         } else if (ATOMstorage(v->vtype) == TYPE_str) {
    1423    37290173 :                 GDKfree(v->val.sval);
    1424    37290507 :                 v->val.sval = NULL;
    1425    37290507 :                 v->len = 0;
    1426   108949194 :         } else if (0 < v->vtype && v->vtype < MAXATOMS && ATOMextern(v->vtype)) {
    1427        2616 :                 GDKfree(v->val.pval);
    1428        2616 :                 v->val.pval = 0;
    1429        2616 :                 v->len = 0;
    1430             :         }
    1431             : }
    1432             : 
    1433             : /*
    1434             :  * Before we return from the interpreter, we should free all
    1435             :  * dynamically allocated objects and adjust the BAT reference counts.
    1436             :  * Early experience shows that for small stack frames the overhead
    1437             :  * is about 200 ms for a 1M function call loop (tst400e). This means that
    1438             :  * for the time being we do not introduce more complex garbage
    1439             :  * administration code.
    1440             :  *
    1441             :  * Also note that for top-level stack frames (no environment available),
    1442             :  * we should retain the value stack because it acts as a global variables.
    1443             :  * This situation is indicated by the 'global' in the stack frame.
    1444             :  * Upon termination of the session, the stack should be cleared.
    1445             :  * Beware that variables may be know polymorphic, their actual
    1446             :  * type should be saved for variables that reside on a global
    1447             :  * stack frame.
    1448             :  */
    1449             : void
    1450      745166 : garbageCollector(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int flag)
    1451             : {
    1452      745166 :         assert(mb->vtop <= mb->vsize);
    1453      745166 :         assert(stk->stktop <= stk->stksize);
    1454             :         (void) flag;
    1455             :         (void) mb;
    1456             :         (void) cntxt;
    1457   169585252 :         for (int k = 0; k < stk->stktop; k++) {
    1458             :                 //  if (isVarCleanup(mb, k) ){
    1459   168840103 :                 ValPtr v = &stk->stk[k];
    1460   168840103 :                 garbageElement(cntxt, v);
    1461   168840086 :                 *v = (ValRecord) {
    1462             :                         .vtype = TYPE_int,
    1463             :                         .val.ival = int_nil,
    1464             :                         .bat = false,
    1465             :                 };
    1466             :                 //  }
    1467             :         }
    1468      745149 : }

Generated by: LCOV version 1.14