LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_instruction.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 480 627 76.6 %
Date: 2024-12-20 21:24:02 Functions: 42 50 84.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)  Author M. Kersten
      15             :  * For documentation see website
      16             :  */
      17             : #include "monetdb_config.h"
      18             : #include "mal_instruction.h"
      19             : #include "mal_function.h"             /* for getPC() */
      20             : #include "mal_utils.h"
      21             : #include "mal_exception.h"
      22             : #include "mal_private.h"
      23             : 
      24             : /* to avoid memory fragmentation stmt and var blocks are allocated in chunks */
      25             : #define MALCHUNK 256
      26             : 
      27             : /* If we encounter an error it can be left behind in the MalBlk
      28             :  * for the upper layers to abandon the track
      29             :  */
      30             : void
      31           0 : addMalException(MalBlkPtr mb, str msg)
      32             : {
      33           0 :         if (msg == NULL)
      34             :                 return;
      35           0 :         if (mb->errors) {
      36           0 :                 mb->errors = concatErrors(mb->errors, msg);
      37             :         } else {
      38           0 :                 mb->errors = dupError(msg);
      39             :         }
      40             : }
      41             : 
      42             : Symbol
      43     3618273 : newSymbol(const char *nme, int kind)
      44             : {
      45     3618273 :         Symbol cur;
      46             : 
      47     3618273 :         assert(kind == COMMANDsymbol || kind == PATTERNsymbol || kind == FUNCTIONsymbol);
      48     3618273 :         if (nme == NULL)
      49             :                 return NULL;
      50     3618273 :         cur = (Symbol) GDKmalloc(sizeof(SymRecord));
      51     3618274 :         if (cur == NULL)
      52             :                 return NULL;
      53     7236549 :         *cur = (SymRecord) {
      54     3618274 :                 .name = putName(nme),
      55             :                 .kind = kind,
      56             :         };
      57     3618275 :         if (cur->name == NULL) {
      58           0 :                 GDKfree(cur);
      59           0 :                 return NULL;
      60             :         }
      61     3618275 :         if (kind == FUNCTIONsymbol) {
      62       50138 :                 cur->def = newMalBlk(STMT_INCREMENT);
      63       50138 :                 if (cur->def == NULL) {
      64           0 :                         GDKfree(cur);
      65           0 :                         return NULL;
      66             :                 }
      67             :         }
      68             :         return cur;
      69             : }
      70             : 
      71             : void
      72     3598330 : freeSymbol(Symbol s)
      73             : {
      74     3598330 :         if (s == NULL)
      75             :                 return;
      76     3598330 :         if (s->def) {
      77       50136 :                 freeMalBlk(s->def);
      78       50137 :                 s->def = NULL;
      79     3548194 :         } else if (s->allocated && s->func) {
      80     1742663 :                 GDKfree((char*)s->func->comment);
      81     1742663 :                 GDKfree((char*)s->func->cname);
      82     1742663 :                 GDKfree(s->func->args);
      83     1742663 :                 GDKfree(s->func);
      84             :         }
      85     3598331 :         GDKfree(s);
      86             : }
      87             : 
      88             : void
      89      201448 : freeSymbolList(Symbol s)
      90             : {
      91      201448 :         Symbol t = s;
      92             : 
      93     3799255 :         while (s) {
      94     3597806 :                 t = s->peer;
      95     3597806 :                 s->peer = NULL;
      96     3597806 :                 freeSymbol(s);
      97     3597806 :                 s = t;
      98             :         }
      99      201449 : }
     100             : 
     101             : int
     102     4067455 : newMalBlkStmt(MalBlkPtr mb, int maxstmts)
     103             : {
     104     4067455 :         InstrPtr *p;
     105     4067455 :         maxstmts = maxstmts % MALCHUNK == 0 ? maxstmts : ((maxstmts / MALCHUNK) + 1) * MALCHUNK;
     106             : 
     107     4067455 :         p = (InstrPtr *) GDKzalloc(sizeof(InstrPtr) * maxstmts);
     108     4068565 :         if (p == NULL)
     109             :                 return -1;
     110     4068565 :         mb->stmt = p;
     111     4068565 :         mb->stop = 0;
     112     4068565 :         mb->ssize = maxstmts;
     113     4068565 :         return 0;
     114             : }
     115             : 
     116             : MalBlkPtr
     117       63088 : newMalBlk(int elements)
     118             : {
     119       63088 :         MalBlkPtr mb;
     120       63088 :         VarRecord *v;
     121             : 
     122       63088 :         mb = (MalBlkPtr) GDKmalloc(sizeof(MalBlkRecord));
     123       63090 :         if (mb == NULL)
     124             :                 return NULL;
     125             : 
     126             :         /* each MAL instruction implies at least one variable
     127             :          * we reserve some extra for constants */
     128       63090 :         assert(elements >= 0);
     129       63090 :         elements += 8;
     130       63090 :         if (elements % MALCHUNK != 0)
     131       63091 :                 elements = (elements / MALCHUNK + 1) * MALCHUNK;
     132       63090 :         v = (VarRecord *) GDKzalloc(sizeof(VarRecord) * elements);
     133       63092 :         if (v == NULL) {
     134           0 :                 GDKfree(mb);
     135           0 :                 return NULL;
     136             :         }
     137       63092 :         *mb = (MalBlkRecord) {
     138             :                 .var = v,
     139             :                 .vsize = elements,
     140             :                 .maxarg = MAXARG,               /* the minimum for each instruction */
     141             :                 .workers = ATOMIC_VAR_INIT(1),
     142             :         };
     143       63092 :         if (newMalBlkStmt(mb, elements) < 0) {
     144           0 :                 GDKfree(mb->var);
     145           0 :                 GDKfree(mb);
     146           0 :                 return NULL;
     147             :         }
     148             :         return mb;
     149             : }
     150             : 
     151             : int
     152       79725 : resizeMalBlk(MalBlkPtr mb, int elements)
     153             : {
     154       79725 :         int i;
     155       79725 :         assert(elements >= 0);
     156       79725 :         if (elements % MALCHUNK != 0)
     157       10447 :                 elements = (elements / MALCHUNK + 1) * MALCHUNK;
     158             : 
     159       79725 :         if (elements > mb->ssize) {
     160       69277 :                 InstrPtr *ostmt = mb->stmt;
     161       69277 :                 mb->stmt = GDKrealloc(mb->stmt, elements * sizeof(InstrPtr));
     162       69277 :                 if (mb->stmt) {
     163    17680576 :                         for (i = mb->ssize; i < elements; i++)
     164    17611299 :                                 mb->stmt[i] = 0;
     165       69277 :                         mb->ssize = elements;
     166             :                 } else {
     167           0 :                         mb->stmt = ostmt;    /* reinstate old pointer */
     168           0 :                         mb->errors = createMalException(mb, 0, TYPE,
     169             :                                                                                         SQLSTATE(HY013) MAL_MALLOC_FAIL);
     170           0 :                         return -1;
     171             :                 }
     172             :         }
     173             :         return 0;
     174             : }
     175             : 
     176             : /* For a MAL session we have to keep the variables around
     177             :  * and only need to reset the instruction pointer
     178             :  */
     179             : void
     180      589874 : resetMalTypes(MalBlkPtr mb, int stop)
     181             : {
     182      589874 :         int i;
     183             : 
     184    28556235 :         for (i = 0; i < stop; i++)
     185    27966361 :                 mb->stmt[i]->typeresolved = false;
     186      589874 :         mb->stop = stop;
     187      589874 :         mb->errors = NULL;
     188      589874 : }
     189             : 
     190             : /* For SQL operations we have to cleanup variables and trim the space
     191             :  * A portion is retained for the next query */
     192             : void
     193      575407 : resetMalBlk(MalBlkPtr mb)
     194             : {
     195      575407 :         int i;
     196      575407 :         InstrPtr *new;
     197      575407 :         VarRecord *vnew;
     198             : 
     199   156365801 :         for (i = 1/*MALCHUNK*/; i < mb->ssize; i++) {
     200   155790340 :                 freeInstruction(mb->stmt[i]);
     201   155790394 :                 mb->stmt[i] = NULL;
     202             :         }
     203      575461 :         if (mb->ssize != MALCHUNK) {
     204       18826 :                 new = GDKrealloc(mb->stmt, sizeof(InstrPtr) * MALCHUNK);
     205       18826 :                 if (new == NULL) {
     206             :                         /* the only place to return an error signal at this stage. */
     207             :                         /* The Client context should be passed around more deeply */
     208           0 :                         mb->errors = createMalException(mb, 0, TYPE,
     209             :                                                                                         SQLSTATE(HY013) MAL_MALLOC_FAIL);
     210           0 :                         return;
     211             :                 }
     212       18826 :                 mb->stmt = new;
     213       18826 :                 mb->ssize = MALCHUNK;
     214             :         }
     215             :         /* Reuse the initial function statement */
     216      575461 :         mb->stop = 1;
     217             : 
     218    66863647 :         for (i = 0; i < mb->vtop; i++) {
     219    66288241 :                 if (mb->var[i].name)
     220      356472 :                         GDKfree(mb->var[i].name);
     221    66288151 :                 mb->var[i].name = NULL;
     222    66288151 :                 if (isVarConstant(mb, i))
     223    18639847 :                         VALclear(&getVarConstant(mb, i));
     224             :         }
     225             : 
     226      575406 :         if (mb->vsize != MALCHUNK) {
     227       27411 :                 vnew = GDKrealloc(mb->var, sizeof(VarRecord) * MALCHUNK);
     228       27411 :                 if (vnew == NULL) {
     229             :                         /* the only place to return an error signal at this stage. */
     230             :                         /* The Client context should be passed around more deeply */
     231           0 :                         mb->errors = createMalException(mb, 0, TYPE,
     232             :                                                                                         SQLSTATE(HY013) MAL_MALLOC_FAIL);
     233           0 :                         return;
     234             :                 }
     235       27411 :                 mb->var = vnew;
     236       27411 :                 mb->vsize = MALCHUNK;
     237             :         }
     238      575406 :         mb->vtop = 0;
     239             : }
     240             : 
     241             : 
     242             : /* The freeMalBlk code is quite defensive. It is used to localize an
     243             :  * illegal reuse of a MAL blk. */
     244             : void
     245       63322 : freeMalBlk(MalBlkPtr mb)
     246             : {
     247       63322 :         int i;
     248             : 
     249    16368036 :         for (i = 0; i < mb->ssize; i++)
     250    16304706 :                 if (mb->stmt[i]) {
     251      177788 :                         freeInstruction(mb->stmt[i]);
     252      177796 :                         mb->stmt[i] = NULL;
     253             :                 }
     254       63330 :         mb->stop = 0;
     255      350453 :         for (i = 0; i < mb->vtop; i++) {
     256      287120 :                 if (mb->var[i].name)
     257       10342 :                         GDKfree(mb->var[i].name);
     258      287123 :                 mb->var[i].name = NULL;
     259      287123 :                 if (isVarConstant(mb, i))
     260       61191 :                         VALclear(&getVarConstant(mb, i));
     261             :         }
     262       63333 :         mb->vtop = 0;
     263       63333 :         GDKfree(mb->stmt);
     264       63334 :         mb->stmt = 0;
     265       63334 :         GDKfree(mb->var);
     266       63334 :         mb->var = 0;
     267             : 
     268       63334 :         mb->binding[0] = 0;
     269       63334 :         mb->tag = 0;
     270       63334 :         mb->memory = 0;
     271       63334 :         if (mb->help)
     272           0 :                 GDKfree(mb->help);
     273       63334 :         mb->help = 0;
     274       63334 :         mb->inlineProp = 0;
     275       63334 :         mb->unsafeProp = 0;
     276       63334 :         freeException(mb->errors);
     277       63333 :         GDKfree(mb);
     278       63333 : }
     279             : 
     280             : /* The routine below should assure that all referenced structures are
     281             :  * private. The copying is memory conservative. */
     282             : MalBlkPtr
     283         241 : copyMalBlk(MalBlkPtr old)
     284             : {
     285         241 :         MalBlkPtr mb;
     286         241 :         int i;
     287             : 
     288         241 :         mb = (MalBlkPtr) GDKzalloc(sizeof(MalBlkRecord));
     289         241 :         if (mb == NULL)
     290             :                 return NULL;
     291             : 
     292         241 :         mb->var = (VarRecord *) GDKzalloc(sizeof(VarRecord) * old->vsize);
     293         241 :         if (mb->var == NULL) {
     294           0 :                 GDKfree(mb);
     295           0 :                 return NULL;
     296             :         }
     297             : 
     298         241 :         mb->vsize = old->vsize;
     299             : 
     300             :         /* copy all variable records */
     301       12308 :         for (i = 0; i < old->vtop; i++) {
     302       12067 :                 mb->var[i] = old->var[i];
     303       12067 :                 if (mb->var[i].name) {
     304         639 :                         mb->var[i].name = GDKstrdup(mb->var[i].name);
     305         639 :                         if (!mb->var[i].name)
     306           0 :                                 goto bailout;
     307             :                 }
     308       12067 :                 if (VALcopy(&(mb->var[i].value), &(old->var[i].value)) == NULL) {
     309           0 :                         mb->vtop = i;
     310           0 :                         goto bailout;
     311             :                 }
     312             :         }
     313         241 :         mb->vtop = old->vtop;
     314             : 
     315         241 :         mb->stmt = (InstrPtr *) GDKzalloc(sizeof(InstrPtr) * old->ssize);
     316         241 :         if (mb->stmt == NULL) {
     317           0 :                 goto bailout;
     318             :         }
     319             : 
     320         241 :         mb->ssize = old->ssize;
     321         241 :         assert(old->stop < old->ssize);
     322       11369 :         for (i = 0; i < old->stop; i++) {
     323       11128 :                 mb->stmt[i] = copyInstruction(old->stmt[i]);
     324       11128 :                 if (mb->stmt[i] == NULL) {
     325           0 :                         mb->stop = i;
     326           0 :                         goto bailout;
     327             :                 }
     328             :         }
     329         241 :         mb->stop = old->stop;
     330         241 :         if (old->help && (mb->help = GDKstrdup(old->help)) == NULL) {
     331           0 :                 goto bailout;
     332             :         }
     333             : 
     334         241 :         strcpy_len(mb->binding, old->binding, sizeof(mb->binding));
     335         241 :         mb->errors = old->errors ? GDKstrdup(old->errors) : 0;
     336         241 :         mb->tag = old->tag;
     337         241 :         mb->runtime = old->runtime;
     338         241 :         mb->calls = old->calls;
     339         241 :         mb->optimize = old->optimize;
     340         241 :         mb->maxarg = old->maxarg;
     341         241 :         mb->inlineProp = old->inlineProp;
     342         241 :         mb->unsafeProp = old->unsafeProp;
     343         241 :         return mb;
     344             : 
     345             :   bailout:
     346           0 :         for (i = 0; i < old->stop; i++)
     347           0 :                 freeInstruction(mb->stmt[i]);
     348           0 :         for (i = 0; i < old->vtop; i++) {
     349           0 :                 if (mb->var[i].name)
     350           0 :                         GDKfree(mb->var[i].name);
     351           0 :                 VALclear(&mb->var[i].value);
     352             :         }
     353           0 :         GDKfree(mb->var);
     354           0 :         GDKfree(mb->stmt);
     355           0 :         GDKfree(mb);
     356           0 :         return NULL;
     357             : }
     358             : 
     359             : /* The MAL records should be managed from a pool to
     360             :  * avoid repeated alloc/free and reduce probability of
     361             :  * memory fragmentation. (todo)
     362             :  * The complicating factor is their variable size,
     363             :  * which leads to growing records as a result of pushArguments
     364             :  * Allocation of an instruction should always succeed.
     365             :  */
     366             : InstrPtr
     367    34613302 : newInstructionArgs(MalBlkPtr mb, const char *modnme, const char *fcnnme,
     368             :                                    int args)
     369             : {
     370    34613302 :         InstrPtr p;
     371             : 
     372    34613302 :         if (mb && mb->errors)
     373             :                 return NULL;
     374    34613287 :         if (args <= 0)
     375             :                 args = 1;
     376    34613287 :         p = GDKmalloc(args * sizeof(p->argv[0]) + offsetof(InstrRecord, argv));
     377    34618795 :         if (p == NULL) {
     378           0 :                 if (mb)
     379           0 :                         mb->errors = createMalException(mb, 0, TYPE,
     380             :                                                                                         SQLSTATE(HY013) MAL_MALLOC_FAIL);
     381           0 :                 return NULL;
     382             :         }
     383    34618795 :         *p = (InstrRecord) {
     384             :                 .maxarg = args,
     385             :                 .typeresolved = false,
     386             :                 .modname = modnme,
     387             :                 .fcnname = fcnnme,
     388             :                 .argc = 1,
     389             :                 .retc = 1,
     390             :                 /* Flow of control instructions are always marked as an assignment
     391             :                  * with modifier */
     392             :                 .token = ASSIGNsymbol,
     393             :         };
     394    34618795 :         memset(p->argv, 0, args * sizeof(p->argv[0]));
     395    34618795 :         p->argv[0] = -1;
     396    34618795 :         return p;
     397             : }
     398             : 
     399             : InstrPtr
     400     4616615 : newInstruction(MalBlkPtr mb, const char *modnme, const char *fcnnme)
     401             : {
     402     4616615 :         return newInstructionArgs(mb, modnme, fcnnme, MAXARG);
     403             : }
     404             : 
     405             : InstrPtr
     406    25295594 : copyInstructionArgs(const InstrRecord *p, int args)
     407             : {
     408    25295594 :         if (args < p->maxarg)
     409             :                 args = p->maxarg;
     410    25295594 :         InstrPtr new = (InstrPtr) GDKmalloc(offsetof(InstrRecord, argv) +
     411             :                                                                                 args * sizeof(p->argv[0]));
     412    25296706 :         if (new == NULL)
     413             :                 return new;
     414    25296706 :         memcpy(new, p,
     415    25296706 :                    offsetof(InstrRecord, argv) + p->maxarg * sizeof(p->argv[0]));
     416    25296706 :         if (args > p->maxarg)
     417     3312183 :                 memset(new->argv + p->maxarg, 0,
     418     3312183 :                            (args - p->maxarg) * sizeof(new->argv[0]));
     419    25296706 :         new->typeresolved = false;
     420    25296706 :         new->maxarg = args;
     421    25296706 :         return new;
     422             : }
     423             : 
     424             : InstrPtr
     425    17841567 : copyInstruction(const InstrRecord *p)
     426             : {
     427    17841567 :         return copyInstructionArgs(p, p->maxarg);
     428             : }
     429             : 
     430             : void
     431      653784 : clrFunction(InstrPtr p)
     432             : {
     433      653784 :         p->token = ASSIGNsymbol;
     434      653784 :         p->fcn = 0;
     435      653784 :         p->blk = 0;
     436      653784 :         p->typeresolved = false;
     437      653784 :         setModuleId(p, NULL);
     438      653843 :         setFunctionId(p, NULL);
     439      653936 : }
     440             : 
     441             : void
     442           0 : clrInstruction(InstrPtr p)
     443             : {
     444           0 :         clrFunction(p);
     445           0 :         memset(p, 0, offsetof(InstrRecord, argv) + p->maxarg * sizeof(p->argv[0]));
     446           0 : }
     447             : 
     448             : void
     449   183993668 : freeInstruction(InstrPtr p)
     450             : {
     451   183993668 :         GDKfree(p);
     452   183912924 : }
     453             : 
     454             : /* Query optimizers walk their way through a MAL program block. They
     455             :  * require some primitives to move instructions around and to remove
     456             :  * superfluous instructions. The removal is based on the assumption
     457             :  * that indeed the instruction belonged to the block. */
     458             : void
     459           0 : removeInstruction(MalBlkPtr mb, InstrPtr p)
     460             : {
     461           0 :         int i;
     462           0 :         for (i = 0; i < mb->stop - 1; i++)
     463           0 :                 if (mb->stmt[i] == p)
     464             :                         break;
     465           0 :         if (i == mb->stop)
     466             :                 return;
     467           0 :         for (; i < mb->stop - 1; i++)
     468           0 :                 mb->stmt[i] = mb->stmt[i + 1];
     469           0 :         mb->stmt[i] = 0;
     470           0 :         mb->stop--;
     471           0 :         assert(i == mb->stop);               /* move statement after stop */
     472           0 :         mb->stmt[i] = p;
     473             : }
     474             : 
     475             : void
     476           0 : removeInstructionBlock(MalBlkPtr mb, int pc, int cnt)
     477             : {
     478           0 :         int i;
     479           0 :         InstrPtr p;
     480           0 :         for (i = pc; i < pc + cnt; i++) {
     481           0 :                 p = getInstrPtr(mb, i);
     482           0 :                 freeInstruction(p);
     483           0 :                 mb->stmt[i] = NULL;
     484           0 :         } for (i = pc; i < mb->stop - cnt; i++)
     485           0 :                 mb->stmt[i] = mb->stmt[i + cnt];
     486           0 :         mb->stop -= cnt;
     487           0 :         for (; i < mb->stop; i++)
     488             :                 mb->stmt[i] = 0;
     489           0 : }
     490             : 
     491             : void
     492           0 : moveInstruction(MalBlkPtr mb, int pc, int target)
     493             : {
     494           0 :         InstrPtr p;
     495           0 :         int i;
     496           0 :         p = getInstrPtr(mb, pc);
     497           0 :         if (pc > target) {
     498           0 :                 for (i = pc; i > target; i--)
     499           0 :                         mb->stmt[i] = mb->stmt[i - 1];
     500           0 :                 mb->stmt[i] = p;
     501             :         } else {
     502           0 :                 for (i = target; i > pc; i--)
     503           0 :                         mb->stmt[i] = mb->stmt[i - 1];
     504           0 :                 mb->stmt[i] = p;
     505             :         }
     506           0 : }
     507             : 
     508             : /* Beware that the first argument of a signature is reserved for the
     509             :  * function return type , which should be equal to the destination
     510             :  * variable type.
     511             :  */
     512             : int
     513      671364 : findVariable(MalBlkPtr mb, const char *name)
     514             : {
     515      671364 :         int i;
     516      671364 :         if (name == NULL)
     517             :                 return -1;
     518     5961727 :         for (i = mb->vtop - 1; i >= 0; i--)
     519     5641884 :                 if (mb->var[i].name && idcmp(name, mb->var[i].name) == 0)
     520      351521 :                         return i;
     521             :         return -1;
     522             : }
     523             : 
     524             : /* The second version of findVariable assumes you have not yet
     525             :  * allocated a private structure. This is particularly useful during
     526             :  * parsing, because most variables are already defined. This way we
     527             :  * safe GDKmalloc/GDKfree. */
     528             : int
     529       54182 : findVariableLength(MalBlkPtr mb, const char *name, int len)
     530             : {
     531       54182 :         int i;
     532     2564110 :         for (i = mb->vtop - 1; i >= 0; i--) {
     533     2521169 :                 const char *s = mb->var[i].name;
     534     2521169 :                 if (s && strncmp(name, s, len) == 0 && s[len] == 0)
     535       11241 :                         return i;
     536             :         }
     537             :         return -1;
     538             : }
     539             : 
     540             : str
     541         174 : getArgDefault(MalBlkPtr mb, InstrPtr p, int idx)
     542             : {
     543         174 :         ValPtr v = &getVarConstant(mb, getArg(p, idx));
     544         174 :         if (v->vtype == TYPE_str)
     545         174 :                 return v->val.sval;
     546             :         return NULL;
     547             : }
     548             : 
     549             : /* Beware, the symbol table structure assumes that it is relatively
     550             :  * cheap to perform a linear search to a variable or constant. */
     551             : static int
     552    66333345 : makeVarSpace(MalBlkPtr mb)
     553             : {
     554    66333345 :         if (mb->vtop >= mb->vsize) {
     555      103824 :                 VarRecord *new;
     556      103824 :                 int s = (mb->vtop / MALCHUNK + 1) * MALCHUNK;
     557      103824 :                 new = (VarRecord *) GDKrealloc(mb->var, s * sizeof(VarRecord));
     558      103824 :                 if (new == NULL) {
     559             :                         /* the only place to return an error signal at this stage. */
     560             :                         /* The Client context should be passed around more deeply */
     561           0 :                         mb->errors = createMalException(mb, 0, TYPE, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     562           0 :                         return -1;
     563             :                 }
     564      103824 :                 memset(new + mb->vsize, 0, (s - mb->vsize) * sizeof(VarRecord));
     565      103824 :                 mb->vsize = s;
     566      103824 :                 mb->var = new;
     567             :         }
     568             :         return 0;
     569             : }
     570             : 
     571             : /* create and initialize a variable record*/
     572             : void
     573    66336812 : setVariableType(MalBlkPtr mb, const int n, malType type)
     574             : {
     575    66336812 :         assert(n >= 0 && n < mb->vtop);
     576    66336812 :         setVarType(mb, n, type);
     577    66336812 :         setRowCnt(mb, n, 0);
     578    66336812 :         clrVarFixed(mb, n);
     579    66336812 :         clrVarUsed(mb, n);
     580    66336812 :         clrVarInit(mb, n);
     581    66336812 :         clrVarDisabled(mb, n);
     582    66336812 :         clrVarConstant(mb, n);
     583    66336812 :         clrVarCleanup(mb, n);
     584    66336812 : }
     585             : 
     586             : char *
     587       25899 : getVarNameIntoBuffer(MalBlkPtr mb, int idx, char *buf)
     588             : {
     589       25899 :         char *s = mb->var[idx].name;
     590       25899 :         if (s == NULL) {
     591       25760 :                 char kind = getVarKind(mb, idx);
     592       51529 :                 (void) snprintf(buf, IDLENGTH, "%c_%d", kind ? kind : REFMARKER, idx);
     593             :         } else {
     594         139 :                 strcpy_len(buf, s, IDLENGTH);
     595             :         }
     596       25899 :         return buf;
     597             : }
     598             : 
     599             : int
     600    66331927 : newVariable(MalBlkPtr mb, const char *name, size_t len, malType type)
     601             : {
     602    66331927 :         int n;
     603    66331927 :         int kind = REFMARKER;
     604    66331927 :         if (mb->errors)
     605             :                 return -1;
     606    66331927 :         if (len >= IDLENGTH) {
     607           1 :                 mb->errors = createMalException(mb, 0, TYPE, "newVariable: id too long");
     608           1 :                 return -1;
     609             :         }
     610    66331926 :         if (makeVarSpace(mb)) {         /* no space for a new variable */
     611             :                 return -1;
     612             :         }
     613    66334040 :         n = mb->vtop;
     614    66334040 :         mb->var[n].name = NULL;
     615    66334040 :         if (name && len > 0) {
     616      366173 :                 char *nme = GDKmalloc(len+1);
     617      366177 :                 if (!nme) {
     618           0 :                         mb->errors = createMalException(mb, 0, TYPE, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     619           0 :                         return -1;
     620             :                 }
     621      366177 :                 mb->var[n].name = nme;
     622     3056559 :                 for (size_t i = 0; i < len; i++)
     623     2690382 :                         nme[i] = name[i];
     624      366177 :                 nme[len] = 0;
     625      366177 :                 kind = nme[0];
     626             :         }
     627    66334044 :         mb->vtop++;
     628    66334044 :         setVarKind(mb, n, kind);
     629    66334044 :         setVariableType(mb, n, type);
     630    66334044 :         return n;
     631             : }
     632             : 
     633             : /* Simplified cloning. */
     634             : int
     635           0 : cloneVariable(MalBlkPtr tm, MalBlkPtr mb, int x)
     636             : {
     637           0 :         int res;
     638           0 :         if (isVarConstant(mb, x))
     639           0 :                 res = cpyConstant(tm, getVar(mb, x));
     640             :         else {
     641           0 :                 res = newTmpVariable(tm, getVarType(mb, x));
     642           0 :                 if (mb->var[x].name)
     643           0 :                         tm->var[x].name = GDKstrdup(mb->var[x].name);
     644             :         }
     645           0 :         if (res < 0)
     646             :                 return res;
     647           0 :         if (isVarFixed(mb, x))
     648           0 :                 setVarFixed(tm, res);
     649           0 :         if (isVarUsed(mb, x))
     650           0 :                 setVarUsed(tm, res);
     651           0 :         if (isVarInit(mb, x))
     652           0 :                 setVarInit(tm, res);
     653           0 :         if (isVarDisabled(mb, x))
     654           0 :                 setVarDisabled(tm, res);
     655           0 :         if (isVarCleanup(mb, x))
     656           0 :                 setVarCleanup(tm, res);
     657           0 :         getVarSTC(tm, x) = getVarSTC(mb, x);
     658           0 :         setVarKind(tm, x, getVarKind(mb, x));
     659           0 :         return res;
     660             : }
     661             : 
     662             : int
     663    65967404 : newTmpVariable(MalBlkPtr mb, malType type)
     664             : {
     665    65967404 :         return newVariable(mb, 0, 0, type);
     666             : }
     667             : 
     668             : int
     669         273 : newTypeVariable(MalBlkPtr mb, malType type)
     670             : {
     671         273 :         int n, i;
     672        1281 :         for (i = 0; i < mb->vtop; i++)
     673        1051 :                 if (isVarTypedef(mb, i) && getVarType(mb, i) == type)
     674             :                         break;
     675         273 :         if (i < mb->vtop)
     676             :                 return i;
     677         230 :         n = newTmpVariable(mb, type);
     678         230 :         if (n >= 0)
     679         230 :                 setVarTypedef(mb, n);
     680             :         return n;
     681             : }
     682             : 
     683             : void
     684       69115 : clearVariable(MalBlkPtr mb, int varid)
     685             : {
     686       69115 :         VarPtr v;
     687       69115 :         v = getVar(mb, varid);
     688       69115 :         if (isVarConstant(mb, varid) || isVarDisabled(mb, varid))
     689       26528 :                 VALclear(&v->value);
     690       69115 :         if (v->name)
     691           0 :                 GDKfree(v->name);
     692       69115 :         v->name = NULL;
     693       69115 :         v->type = 0;
     694       69115 :         v->constant = 0;
     695       69115 :         v->typevar = 0;
     696       69115 :         v->fixedtype = 0;
     697       69115 :         v->cleanup = 0;
     698       69115 :         v->initialized = 0;
     699       69115 :         v->used = 0;
     700       69115 :         v->rowcnt = 0;
     701       69115 :         v->eolife = 0;
     702       69115 :         v->stc = 0;
     703       69115 : }
     704             : 
     705             : void
     706          82 : freeVariable(MalBlkPtr mb, int varid)
     707             : {
     708          82 :         clearVariable(mb, varid);
     709          82 : }
     710             : 
     711             : /* A special action is to reduce the variable space by removing all
     712             :  * that do not contribute.
     713             :  * All temporary variables are renamed in the process to trim the varid.
     714             :  */
     715             : void
     716           3 : trimMalVariables_(MalBlkPtr mb, MalStkPtr glb)
     717             : {
     718           3 :         int *alias, cnt = 0, i, j;
     719           3 :         InstrPtr q;
     720           3 :         if (mb->vtop == 0)
     721             :                 return;
     722           3 :         alias = (int *) GDKzalloc(mb->vtop * sizeof(int));
     723           3 :         if (alias == NULL)
     724             :                 return;                                 /* forget it if we run out of memory *//* build the alias table */
     725         677 :         for (i = 0; i < mb->vtop; i++) {
     726         674 :                 if (isVarUsed(mb, i) == 0) {
     727          82 :                         if (glb && i < glb->stktop && isVarConstant(mb, i))
     728           0 :                                 VALclear(&glb->stk[i]);
     729          82 :                         freeVariable(mb, i);
     730          82 :                         continue;
     731             :                 }
     732         592 :                 if (i > cnt) {                       /* remap temporary variables */
     733         532 :                         VarRecord t = mb->var[cnt];
     734         532 :                         mb->var[cnt] = mb->var[i];
     735         532 :                         mb->var[i] = t;
     736             :                 }                                               /* valgrind finds a leak when we move these variable record * pointers around. */
     737         592 :                 alias[i] = cnt;
     738         592 :                 if (glb && i < glb->stktop && i != cnt) {
     739           0 :                         glb->stk[cnt] = glb->stk[i];
     740           0 :                         VALempty(&glb->stk[i]);
     741             :                 }
     742         592 :                 cnt++;
     743             :         }                                                       /* remap all variable references to their new position. */
     744           3 :         if (cnt < mb->vtop) {
     745         385 :                 for (i = 0; i < mb->stop; i++) {
     746         382 :                         q = getInstrPtr(mb, i);
     747        2271 :                         for (j = 0; j < q->argc; j++) {
     748        1889 :                                 getArg(q, j) = alias[getArg(q, j)];
     749             :                         }
     750             :                 }
     751           3 :                 mb->vtop = cnt;
     752             :         }
     753           3 :         GDKfree(alias);
     754             : }
     755             : 
     756             : void
     757           3 : trimMalVariables(MalBlkPtr mb, MalStkPtr stk)
     758             : {
     759           3 :         int i, j;
     760           3 :         InstrPtr q;                                     /* reset the use bit for all non-signature arguments */
     761         677 :         for (i = 0; i < mb->vtop; i++)
     762         674 :                 clrVarUsed(mb, i);              /* build the use table */
     763         385 :         for (i = 0; i < mb->stop; i++) {
     764         382 :                 q = getInstrPtr(mb, i);
     765        2271 :                 for (j = 0; j < q->argc; j++)
     766        1889 :                         setVarUsed(mb, getArg(q, j));
     767             :         }
     768           3 :         trimMalVariables_(mb, stk);
     769           3 : }
     770             : 
     771             : /* MAL constants
     772             :  * Constants are stored in the symbol table and referenced by a
     773             :  * variable identifier. This means that per MAL instruction, we may
     774             :  * end up with MAXARG entries in the symbol table. This may lead to
     775             :  * long searches for variables. An optimization strategy deployed in
     776             :  * the current implementation is to look around for a similar
     777             :  * (constant) definition and to reuse its identifier. This avoids an
     778             :  * exploding symbol table with a lot of temporary variables (as in
     779             :  * tst400cHuge)
     780             :  *
     781             :  * But then the question becomes how far to search? Searching through
     782             :  * all variables is only useful when the list remains short or when
     783             :  * the constant-variable-name is easily derivable from its literal
     784             :  * value and a hash-based index leads you quickly to it.
     785             :  *
     786             :  * For the time being, we use a MAL system parameter, MAL_VAR_WINDOW,
     787             :  * to indicate the number of symbol table entries to consider. Setting
     788             :  * it to >= MAXARG will at least capture repeated use of a constant
     789             :  * within a single function call or repeated use within a small block
     790             :  * of code.
     791             :  *
     792             :  * The final step is to prepare a GDK value record, from which the
     793             :  * internal representation can be obtained during MAL interpretation.
     794             :  *
     795             :  * The constant values are linked together to improve searching
     796             :  * them. This start of the constant list is kept in the MalBlk.
     797             :  *
     798             :  * Conversion of a constant to another type is limited to well-known
     799             :  * coercion rules. Errors are reported and the nil value is set. */
     800             : 
     801             : /* Converts the constant in vr to the MAL type type.  Conversion is
     802             :  * done in the vr struct. */
     803             : str
     804      280594 : convertConstant(int type, ValPtr vr)
     805             : {
     806      280594 :         if (type > GDKatomcnt)
     807           0 :                 throw(SYNTAX, "convertConstant", "type index out of bound");
     808      280594 :         if (vr->vtype == type)
     809             :                 return MAL_SUCCEED;
     810      280591 :         if (isaBatType(type)) { /* BAT variables can only be set to nil */
     811           0 :                 if (vr->vtype != TYPE_void)
     812           0 :                         throw(SYNTAX, "convertConstant", "BAT conversion error");
     813           0 :                 VALclear(vr);
     814           0 :                 vr->vtype = getBatType(type);
     815           0 :                 vr->bat = true;
     816           0 :                 vr->val.bval = bat_nil;
     817           0 :                 return MAL_SUCCEED;
     818             :         }
     819      280591 :         if (type == TYPE_ptr) {         /* all coercions should be avoided to protect against memory probing */
     820          32 :                 if (vr->vtype == TYPE_void) {
     821          32 :                         VALclear(vr);
     822          32 :                         vr->vtype = type;
     823          32 :                         vr->val.pval = NULL;
     824          32 :                         return MAL_SUCCEED;
     825             :                 }
     826           0 :                 if (vr->vtype != type)
     827           0 :                         throw(SYNTAX, "convertConstant", "pointer conversion error");
     828             :                 return MAL_SUCCEED;
     829             :         }
     830      280559 :         if (type == TYPE_any) {
     831             : #ifndef DEBUG_MAL_INSTR
     832             :                 assert(0);
     833             : #endif
     834           0 :                 throw(SYNTAX, "convertConstant", "missing type");
     835             :         }
     836      280559 :         if (VALconvert(type, vr) == NULL) {
     837           3 :                 if (vr->vtype == TYPE_str)
     838           0 :                         throw(SYNTAX, "convertConstant", "parse error in '%s'", vr->val.sval);
     839           3 :                 throw(SYNTAX, "convertConstant", "coercion failed");
     840             :         }
     841             :         return MAL_SUCCEED;
     842             : }
     843             : 
     844             : int
     845    52275056 : fndConstant(MalBlkPtr mb, const ValRecord *cst, int depth)
     846             : {
     847    52275056 :         int i, k;
     848    52275056 :         const void *p;                          /* pointers never match */
     849    52275056 :         if (ATOMstorage(cst->vtype) == TYPE_ptr)
     850             :                 return -1;
     851    52117048 :         p = VALptr(cst);
     852    52117048 :         k = mb->vtop - depth;
     853    52117048 :         if (k < 0)
     854             :                 k = 0;
     855   590602509 :         for (i = k; i < mb->vtop - 1; i++) {
     856   570469352 :                 VarPtr v = getVar(mb, i);
     857   570469352 :                 if (v->constant) {
     858   200139329 :                         if (v && v->type == cst->vtype &&
     859   116627875 :                                         v->value.len == cst->len &&
     860   192349930 :                                         isaBatType(v->type) == cst->bat &&
     861    96182751 :                                         ATOMcmp(cst->vtype, VALptr(&v->value), p) == 0)
     862    31973122 :                                 return i;
     863             :                 }
     864             :         }
     865             :         return -1;
     866             : }
     867             : 
     868             : int
     869        3388 : cpyConstant(MalBlkPtr mb, VarPtr vr)
     870             : {
     871        3388 :         int i;
     872        3388 :         ValRecord cst;
     873        3388 :         if (VALcopy(&cst, &vr->value) == NULL)
     874             :                 return -1;
     875        3388 :         i = defConstant(mb, vr->type, &cst);
     876        3388 :         if (i < 0)
     877             :                 return -1;
     878             :         return i;
     879             : }
     880             : 
     881             : int
     882    46997158 : defConstant(MalBlkPtr mb, int type, ValPtr cst)
     883             : {
     884    46997158 :         int k;
     885    46997158 :         str msg;
     886             : 
     887    46997158 :         assert(!isaBatType(type) || cst->bat);
     888    46997158 :         cst->bat = false;
     889    46997158 :         if (isaBatType(type)) {
     890      474096 :                 if (cst->vtype == TYPE_void) {
     891      474095 :                         cst->vtype = getBatType(type);
     892      474095 :                         cst->bat = true;
     893      474095 :                         cst->val.bval = bat_nil;
     894             :                 } else {
     895           1 :                         mb->errors = createMalException(mb, 0, TYPE, "BAT coercion error");
     896           1 :                         VALclear(cst);  // it could contain allocated space
     897           1 :                         return -1;
     898             :                 }
     899    46523062 :         } else if (cst->vtype != type && !isPolyType(type)) {
     900        1915 :                 int otype = cst->vtype;
     901        1915 :                 assert(type != TYPE_any);       /* help Coverity */
     902        1915 :                 msg = convertConstant(getBatType(type), cst);
     903        1916 :                 if (msg) {
     904           3 :                         str ft, tt;                     /* free old value */
     905           3 :                         ft = getTypeName(otype);
     906           3 :                         tt = getTypeName(type);
     907           3 :                         if (ft && tt)
     908           3 :                                 mb->errors = createMalException(mb, 0, TYPE,
     909             :                                                                                                 "constant coercion error from %s to %s",
     910             :                                                                                                 ft, tt);
     911             :                         else
     912           0 :                                 mb->errors = createMalException(mb, 0, TYPE,
     913             :                                                                                                 "constant coercion error");
     914           3 :                         GDKfree(ft);
     915           3 :                         GDKfree(tt);
     916           3 :                         freeException(msg);
     917           3 :                         VALclear(cst);          /* it could contain allocated space */
     918           3 :                         return -1;
     919             :                 } else {
     920        1913 :                         assert(cst->vtype == type);
     921             :                 }
     922             :         }
     923    46997155 :         if (cst->vtype != TYPE_any) {
     924    46998211 :                 k = fndConstant(mb, cst, MAL_VAR_WINDOW);
     925    46999064 :                 if (k >= 0) {                                /* protect against leaks coming from constant reuse */
     926    28307804 :                         VALclear(cst);
     927    28307804 :                         return k;
     928             :                 }
     929             :         }
     930    18690204 :         k = newTmpVariable(mb, type);
     931    18732244 :         if (k < 0) {
     932           0 :                 VALclear(cst);
     933           0 :                 return -1;
     934             :         }
     935    18732244 :         setVarConstant(mb, k);
     936    18732244 :         setVarFixed(mb, k);
     937    18732244 :         if (type >= 0 && type < GDKatomcnt && ATOMextern(type))
     938     4756756 :                 setVarCleanup(mb, k);
     939             :         else
     940    13975488 :                 clrVarCleanup(mb, k);   /* if cst is external, we give its allocated buffer away, so clear * it to avoid confusion */
     941    18732244 :         getVarConstant(mb, k) = *cst;
     942    18732244 :         VALempty(cst);
     943    18732244 :         return k;
     944             : }
     945             : 
     946             : /* Argument handling
     947             :  * The number of arguments for procedures is currently
     948             :  * limited. Furthermore, we should assure that no variable is
     949             :  * referenced before being assigned. Failure to obey should mark the
     950             :  * instruction as type-error. */
     951             : static InstrPtr
     952         319 : extendInstruction(MalBlkPtr mb, InstrPtr p)
     953             : {
     954         319 :         InstrPtr pn = p;
     955         319 :         if (p->argc == p->maxarg) {
     956         319 :                 int space = p->maxarg * sizeof(p->argv[0]) + offsetof(InstrRecord, argv);
     957         319 :                 pn = (InstrPtr) GDKrealloc(p, space + MAXARG * sizeof(p->argv[0]));
     958         319 :                 if (pn == NULL) {               /* In the exceptional case we can not allocate more space * then we show an exception, mark the block as erroneous * and leave the instruction as is. */
     959           0 :                         mb->errors = createMalException(mb, 0, TYPE,
     960             :                                                                                         SQLSTATE(HY013) MAL_MALLOC_FAIL);
     961           0 :                         return p;
     962             :                 }
     963         319 :                 memset(((char *) pn) + space, 0, MAXARG * sizeof(pn->argv[0]));
     964         319 :                 pn->maxarg += MAXARG;
     965             :         }
     966             :         return pn;
     967             : }
     968             : 
     969             : InstrPtr
     970   175209639 : pushArgument(MalBlkPtr mb, InstrPtr p, int varid)
     971             : {
     972   175209639 :         if (p == NULL || mb->errors)
     973             :                 return p;
     974   175209639 :         if (varid < 0) {                     /* leave everything as is in this exceptional programming error */
     975           0 :                 mb->errors = createMalException(mb, 0, TYPE, "improper variable id");
     976           0 :                 return p;
     977             :         }
     978   175209639 :         if (p->argc == p->maxarg) {
     979             : #ifndef NDEBUG
     980        1011 :                 for (int i = 0; i < mb->stop; i++)
     981         692 :                         assert(mb->stmt[i] != p);
     982             : #endif
     983         319 :                 p = extendInstruction(mb, p);
     984         319 :                 if (mb->errors)
     985             :                         return p;
     986             :         }                                                       /* protect against the case that the instruction is malloced in isolation */
     987   175209639 :         if (mb->maxarg < p->maxarg)
     988       12468 :                 mb->maxarg = p->maxarg;
     989   175209639 :         p->argv[p->argc++] = varid;
     990   175209639 :         return p;
     991             : }
     992             : 
     993             : InstrPtr
     994      860434 : setArgument(MalBlkPtr mb, InstrPtr p, int idx, int varid)
     995             : {
     996      860434 :         int i;
     997      860434 :         if (p == NULL || mb->errors)
     998             :                 return p;
     999      860450 :         p = pushArgument(mb, p, varid); /* make space */
    1000      864405 :         for (i = p->argc - 1; i > idx; i--)
    1001        3952 :                 getArg(p, i) = getArg(p, i - 1);
    1002      860453 :         getArg(p, i) = varid;
    1003      860453 :         return p;
    1004             : }
    1005             : 
    1006             : InstrPtr
    1007      861380 : pushReturn(MalBlkPtr mb, InstrPtr p, int varid)
    1008             : {
    1009      861380 :         if (p == NULL || mb->errors)
    1010             :                 return p;
    1011      861380 :         if (p->retc == 1 && p->argv[0] == -1) {
    1012         931 :                 p->argv[0] = varid;
    1013         931 :                 return p;
    1014             :         }
    1015      860449 :         p = setArgument(mb, p, p->retc, varid);
    1016      860463 :         p->retc++;
    1017      860463 :         return p;
    1018             : }
    1019             : 
    1020             : /* Store the information of a destination variable in the signature
    1021             :  * structure of each instruction. This code is largely equivalent to
    1022             :  * pushArgument, but it is more efficient in searching and collecting
    1023             :  * the information.
    1024             :  * TODO */
    1025             : /* swallows name argument */
    1026             : InstrPtr
    1027        5435 : pushArgumentId(MalBlkPtr mb, InstrPtr p, const char *name)
    1028             : {
    1029        5435 :         int v;
    1030        5435 :         if (p == NULL || mb->errors)
    1031             :                 return p;
    1032        5435 :         v = findVariable(mb, name);
    1033        5435 :         if (v < 0) {
    1034         389 :                 size_t namelen = strlen(name);
    1035         389 :                 if ((v = newVariable(mb, name, namelen, getAtomIndex(name, namelen, TYPE_any))) < 0) {
    1036             :                         /* set the MAL block to erroneous and simply return without
    1037             :                          * doing anything */
    1038             :                         /* mb->errors already set */
    1039             :                         return p;
    1040             :                 }
    1041             :         }
    1042        5434 :         return pushArgument(mb, p, v);
    1043             : }
    1044             : 
    1045             : /* The alternative is to remove arguments from an instruction
    1046             :  * record. This is typically part of instruction constructions. */
    1047             : void
    1048     1480385 : delArgument(InstrPtr p, int idx)
    1049             : {
    1050     1480385 :         int i;
    1051     2256435 :         for (i = idx; i < p->argc - 1; i++)
    1052      776050 :                 p->argv[i] = p->argv[i + 1];
    1053     1480385 :         p->argc--;
    1054     1480385 :         if (idx < p->retc)
    1055      182690 :                 p->retc--;
    1056     1480385 : }
    1057             : 
    1058             : void
    1059       35573 : setArgType(MalBlkPtr mb, InstrPtr p, int i, int tpe)
    1060             : {
    1061       35573 :         assert(p->argv[i] < mb->vsize);
    1062       35573 :         setVarType(mb, getArg(p, i), tpe);
    1063       35573 : }
    1064             : 
    1065             : void
    1066           0 : setReturnArgument(InstrPtr p, int i)
    1067             : {
    1068           0 :         setDestVar(p, i);
    1069           0 : }
    1070             : 
    1071             : malType
    1072           0 : destinationType(MalBlkPtr mb, InstrPtr p)
    1073             : {
    1074           0 :         if (p->argc > 0)
    1075           0 :                 return getVarType(mb, getDestVar(p));
    1076             :         return TYPE_any;
    1077             : }
    1078             : 
    1079             : /* For polymorphic instructions we should keep around the maximal
    1080             :  * index to later allocate sufficient space for type resolutions maps.
    1081             :  * Beware, that we should only consider the instruction polymorphic if
    1082             :  * it has a positive index or belongs to the signature.
    1083             :  * BATs can only have a polymorphic type at the tail.
    1084             :  */
    1085             : inline void
    1086        9251 : setPolymorphic(InstrPtr p, int tpe, int force /* just any isn't polymorphic */)
    1087             : {
    1088        9251 :         int any = isAnyExpression(tpe) || tpe == TYPE_any, index = 0;
    1089        9251 :         if ((force == FALSE && tpe == TYPE_any) || !any)
    1090             :                 return;
    1091          34 :         if (getTypeIndex(tpe) > 0)
    1092             :                 index = getTypeIndex(tpe);
    1093          34 :         if (any && (index + 1) >= p->polymorphic)
    1094          31 :                 p->polymorphic = index + 1;
    1095             : }
    1096             : 
    1097             : /* Instructions are simply appended to a MAL block. It should always succeed.
    1098             :  * The assumption is to push it when you are completely done with its preparation.
    1099             :  */
    1100             : void
    1101   298685100 : pushInstruction(MalBlkPtr mb, InstrPtr p)
    1102             : {
    1103   298685100 :         int i;
    1104   298685100 :         InstrPtr q;
    1105   298685100 :         if (p == NULL)
    1106             :                 return;
    1107   298685100 :         if (mb->stop + 1 >= mb->ssize) {
    1108       69277 :                 int s = (mb->ssize / MALCHUNK + 1) * MALCHUNK;
    1109       69277 :                 if (resizeMalBlk(mb, s) < 0) {
    1110             :                         /* we are now left with the situation that the new
    1111             :                          * instruction is dangling.  The hack is to take an
    1112             :                          * instruction out of the block that is likely not
    1113             :                          * referenced independently.  The last resort is to take the
    1114             :                          * first, which should always be there.  This assumes that
    1115             :                          * no references are kept elsewhere to the statement. */
    1116           0 :                         assert(mb->errors != NULL);
    1117           0 :                         for (i = 1; i < mb->stop; i++) {
    1118           0 :                                 q = getInstrPtr(mb, i);
    1119           0 :                                 if (q->token == REMsymbol) {
    1120           0 :                                         freeInstruction(q);
    1121           0 :                                         mb->stmt[i] = p;
    1122           0 :                                         return;
    1123             :                                 }
    1124             :                         }
    1125           0 :                         freeInstruction(getInstrPtr(mb, 0));
    1126           0 :                         mb->stmt[0] = p;
    1127           0 :                         return;
    1128             :                 }
    1129             :         }
    1130   298685100 :         if (mb->stmt[mb->stop])
    1131       19089 :                 freeInstruction(mb->stmt[mb->stop]);
    1132   298701814 :         p->pc = mb->stop;
    1133   298701814 :         mb->stmt[mb->stop++] = p;
    1134             : }

Generated by: LCOV version 1.14