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

Generated by: LCOV version 1.14