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

Generated by: LCOV version 1.14