LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_module.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 164 206 79.6 %
Date: 2024-04-25 20:03:45 Functions: 17 19 89.5 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * (author) M. L. Kersten
      15             :  * All symbols are collected in modules. Modules are either global
      16             :  * or private for the user. The latter are known as 'user' module functions
      17             :  * and reside within the Client record.
      18             :  */
      19             : 
      20             : #include "monetdb_config.h"
      21             : #include "mal_module.h"
      22             : #include "mal_function.h"             /* for printFunction() */
      23             : #include "mal_namespace.h"
      24             : #include "mal_client.h"
      25             : #include "mal_interpreter.h"
      26             : #include "mal_listing.h"
      27             : #include "mal_private.h"
      28             : 
      29             : /*
      30             :  * Definition of a new module may interfere with concurrent actions.
      31             :  * A jump table is mainted to provide a quick start in the module
      32             :  * table to find the correct one.
      33             :  *
      34             :  * All modules are persistent during a server session
      35             :  */
      36             : 
      37             : #define MODULE_HASH_SIZE 1024
      38             : static Module moduleIndex[MODULE_HASH_SIZE] = { NULL };
      39             : 
      40             : MALfcn
      41          14 : findFunctionImplementation(const char *cname)
      42             : {
      43       12140 :         for (int i = 0; i < MODULE_HASH_SIZE; i++) {
      44       12137 :                 if (moduleIndex[i] != NULL) {
      45      210319 :                         for (int j = 0; j < MAXSCOPE; j++) {
      46      209503 :                                 Symbol s;
      47      209503 :                                 if ((s = moduleIndex[i]->space[j]) != NULL) {
      48      121437 :                                         do {
      49      121437 :                                                 if (s->def &&
      50      121437 :                                                         strcmp(s->def->binding, cname) == 0 &&
      51          14 :                                                         s->def->stmt &&s->def->stmt[0] &&
      52          14 :                                                         s->def->stmt[0]->fcn) {
      53          11 :                                                         return s->def->stmt[0]->fcn;
      54             :                                                 }
      55      121426 :                                         } while ((s = s->peer) != NULL);
      56             :                                 }
      57             :                         }
      58             :                 }
      59             :         }
      60             :         return NULL;
      61             : }
      62             : 
      63             : BAT *
      64           0 : getModules(void)
      65             : {
      66           0 :         BAT *b = COLnew(0, TYPE_str, 100, TRANSIENT);
      67           0 :         int i;
      68           0 :         Module s, n;
      69             : 
      70           0 :         if (!b)
      71             :                 return NULL;
      72           0 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
      73           0 :                 s = moduleIndex[i];
      74           0 :                 while (s) {
      75           0 :                         if (BUNappend(b, s->name, FALSE) != GDK_SUCCEED) {
      76           0 :                                 BBPreclaim(b);
      77           0 :                                 return NULL;
      78             :                         }
      79           0 :                         n = s->link;
      80           0 :                         while (n)
      81           0 :                                 n = n->link;
      82             :                         s = s->link;
      83             :                 }
      84             :         }
      85             :         return b;
      86             : }
      87             : 
      88             : // perform sanity check on duplicate occurrences as well
      89             : void
      90           0 : dumpModules(stream *out)
      91             : {
      92           0 :         int i;
      93           0 :         Module s, n;
      94           0 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
      95           0 :                 s = moduleIndex[i];
      96           0 :                 while (s) {
      97           0 :                         mnstr_printf(out, "[%d] module %s\n", i, s->name);
      98           0 :                         n = s->link;
      99           0 :                         while (n) {
     100           0 :                                 if (n == s)
     101           0 :                                         mnstr_printf(out,
     102             :                                                                  "ASSERTION error, double occurrence of symbol in symbol table\n");
     103           0 :                                 n = n->link;
     104             :                         }
     105           0 :                         s = s->link;
     106             :                 }
     107             :         }
     108           0 : }
     109             : 
     110             : /* Remove all globally known functions */
     111             : void
     112         334 : mal_module_reset(void)
     113             : {
     114         334 :         int i;
     115         334 :         Module m;
     116             : 
     117      342350 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     118      342016 :                 m = moduleIndex[i];
     119      342016 :                 moduleIndex[i] = 0;
     120      364699 :                 while (m) {
     121       22683 :                         Module next = m->link;
     122       22683 :                         freeModule(m);
     123       22683 :                         m = next;
     124             :                 }
     125             :         }
     126         334 : }
     127             : 
     128             : static int
     129    58759606 : getModuleIndex(const char *name)
     130             : {
     131    58759606 :         return (int) (strHash(name) % MODULE_HASH_SIZE);
     132             : }
     133             : 
     134             : static void
     135       22683 : clrModuleIndex(Module cur)
     136             : {
     137       22683 :         int index = getModuleIndex(cur->name);
     138       22683 :         Module prev = NULL;
     139       22683 :         Module m = moduleIndex[index];
     140       22683 :         while (m) {
     141           0 :                 if (m == cur) {
     142           0 :                         if (!prev) {
     143           0 :                                 moduleIndex[index] = m->link;
     144             :                         } else {
     145           0 :                                 prev->link = m->link;
     146             :                         }
     147           0 :                         return;
     148             :                 }
     149           0 :                 prev = m;
     150           0 :                 m = m->link;
     151             :         }
     152             : }
     153             : 
     154             : static void
     155       22811 : addModuleToIndex(Module cur)
     156             : {
     157       22811 :         int index = getModuleIndex(cur->name);
     158       22811 :         cur->link = moduleIndex[index];
     159       22811 :         moduleIndex[index] = cur;
     160       22811 : }
     161             : 
     162             : Module
     163    58714112 : getModule(const char *name)
     164             : {
     165    58714112 :         int index = getModuleIndex(name);
     166    58714112 :         Module m = moduleIndex[index];
     167    58715148 :         while (m) {
     168    58680137 :                 if (name == m->name)
     169    58679101 :                         return m;
     170        1036 :                 m = m->link;
     171             :         }
     172             :         return NULL;
     173             : }
     174             : 
     175             : void
     176          12 : getModuleList(Module **out, int *length)
     177             : {
     178          12 :         int i;
     179          12 :         int moduleCount = 0;
     180          12 :         int currentIndex = 0;
     181       12300 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     182       12288 :                 Module m = moduleIndex[i];
     183       13110 :                 while (m) {
     184         822 :                         moduleCount++;
     185         822 :                         m = m->link;
     186             :                 }
     187             :         }
     188          12 :         *out = GDKzalloc(moduleCount * sizeof(Module));
     189          12 :         if (*out == NULL) {
     190             :                 return;
     191             :         }
     192          12 :         *length = moduleCount;
     193             : 
     194       12300 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     195       12288 :                 Module m = moduleIndex[i];
     196       13110 :                 while (m) {
     197         822 :                         (*out)[currentIndex++] = m;
     198         822 :                         m = m->link;
     199             :                 }
     200             :         }
     201             : }
     202             : 
     203             : void
     204          12 : freeModuleList(Module *list)
     205             : {
     206          12 :         GDKfree(list);
     207          12 : }
     208             : 
     209             : /*
     210             :  * Module scope management
     211             :  * It will contain the symbol table of all globally accessible functions.
     212             :  */
     213             : Module
     214       22811 : globalModule(const char *nme)
     215             : {
     216       22811 :         Module cur;
     217             : 
     218             :         // Global modules are not named 'user'
     219       22811 :         assert(strcmp(nme, "user"));
     220       22811 :         nme = putName(nme);
     221       22811 :         if (nme == NULL)
     222             :                 return NULL;
     223       22811 :         cur = (Module) GDKzalloc(sizeof(ModuleRecord));
     224       22811 :         if (cur == NULL)
     225             :                 return NULL;
     226       22811 :         cur->name = nme;
     227       22811 :         cur->link = NULL;
     228       22811 :         addModuleToIndex(cur);
     229       22811 :         return cur;
     230             : }
     231             : 
     232             : /* Every client record has a private module name 'user'
     233             :  * for keeping around non-shared functions */
     234             : Module
     235       38562 : userModule(void)
     236             : {
     237       38562 :         Module cur;
     238             : 
     239       38562 :         cur = (Module) GDKzalloc(sizeof(ModuleRecord));
     240       38562 :         if (cur == NULL)
     241             :                 return NULL;
     242       38562 :         cur->name = putName("user");
     243       38562 :         if (cur->name == NULL) {
     244           0 :                 GDKfree(cur);
     245           0 :                 return NULL;
     246             :         }
     247       38562 :         cur->link = NULL;
     248       38562 :         return cur;
     249             : }
     250             : 
     251             : /*
     252             :  * The scope can be fixed. This is used by the parser.
     253             :  * Reading a module often calls for creation first.
     254             :  */
     255             : Module
     256           8 : fixModule(const char *nme)
     257             : {
     258           8 :         Module m;
     259             : 
     260           8 :         m = getModule(nme);
     261           8 :         if (m)
     262             :                 return m;
     263           4 :         return globalModule(nme);
     264             : }
     265             : 
     266             : /*
     267             :  * The freeModule operation throws away a symbol without
     268             :  * concerns on it whereabouts in the scope structure.
     269             :  */
     270             : static void
     271       61244 : freeSubScope(Module scope)
     272             : {
     273       61244 :         int i;
     274       61244 :         Symbol s;
     275             : 
     276    15739125 :         for (i = 0; i < MAXSCOPE; i++) {
     277    15677881 :                 if (scope->space[i]) {
     278      200317 :                         s = scope->space[i];
     279      200317 :                         scope->space[i] = NULL;
     280      200317 :                         freeSymbolList(s);
     281             :                 }
     282             :         }
     283       61244 : }
     284             : 
     285             : void
     286       61244 : freeModule(Module m)
     287             : {
     288       61244 :         Symbol s;
     289             : 
     290       61244 :         if (m == NULL)
     291             :                 return;
     292       61244 :         if ((s = findSymbolInModule(m, "epilogue")) != NULL) {
     293        2326 :                 InstrPtr pci = getInstrPtr(s->def, 0);
     294        2326 :                 if (pci && pci->token == COMMANDsymbol && pci->argc == 1) {
     295        2326 :                         int status = 0;
     296        2326 :                         str ret = MAL_SUCCEED;
     297             : 
     298        2326 :                         assert(pci->fcn != NULL);
     299        2326 :                         ret = (*(str (*)(int *)) pci->fcn) (&status);
     300        2326 :                         freeException(ret);
     301        2326 :                         (void) status;
     302             :                 }
     303             :         }
     304       61244 :         freeSubScope(m);
     305       61243 :         if (strcmp(m->name, "user")) {
     306       22683 :                 clrModuleIndex(m);
     307             :         }
     308       61243 :         if (m->help)
     309           0 :                 GDKfree(m->help);
     310       61243 :         GDKfree(m);
     311             : }
     312             : 
     313             : /*
     314             :  * After filling in a structure it is added to the multi-level symbol
     315             :  * table.  We keep a skip list of similarly named function symbols.
     316             :  * This speeds up searching provided the modules adhere to the
     317             :  * structure and group the functions as well.
     318             :  */
     319             : void
     320     3486613 : insertSymbol(Module scope, Symbol prg)
     321             : {
     322     3486613 :         InstrPtr sig;
     323     3486613 :         int t;
     324     3486613 :         Module c;
     325             : 
     326     3486613 :         assert(scope);
     327     3486613 :         sig = getSignature(prg);
     328     3486613 :         if (getModuleId(sig) && getModuleId(sig) != scope->name) {
     329             :                 /* move the definition to the proper place */
     330             :                 /* default scope is the last resort */
     331           0 :                 c = findModule(scope, getModuleId(sig));
     332           0 :                 if (c)
     333     3486613 :                         scope = c;
     334             :         }
     335     3486613 :         t = getSymbolIndex(getFunctionId(sig));
     336     3486613 :         if (scope->space[t] == prg) {
     337             :                 /* already known, last inserted */
     338             :         } else {
     339     3486603 :                 prg->peer = scope->space[t];
     340     3486603 :                 scope->space[t] = prg;
     341     3486603 :                 if (prg->peer && idcmp(prg->name, prg->peer->name) == 0)
     342     2897889 :                         prg->skip = prg->peer->skip;
     343             :                 else
     344      588714 :                         prg->skip = prg->peer;
     345             :         }
     346     3486613 :         assert(prg != prg->peer);
     347     3486613 : }
     348             : 
     349             : /*
     350             :  * Removal of elements from the symbol table should be
     351             :  * done with care. For, it should be assured that
     352             :  * there are no references to the definition at the
     353             :  * moment of removal. This situation can not easily
     354             :  * checked at runtime, without tremendous overhead.
     355             :  */
     356             : void
     357         549 : deleteSymbol(Module scope, Symbol prg)
     358             : {
     359         549 :         InstrPtr sig;
     360         549 :         int t;
     361             : 
     362         549 :         sig = getSignature(prg);
     363         549 :         if (getModuleId(sig) && getModuleId(sig) != scope->name) {
     364             :                 /* move the definition to the proper place */
     365             :                 /* default scope is the last resort */
     366           0 :                 Module c = findModule(scope, getModuleId(sig));
     367           0 :                 if (c)
     368         549 :                         scope = c;
     369             :         }
     370         549 :         t = getSymbolIndex(getFunctionId(sig));
     371         549 :         if (scope->space[t] == prg) {
     372         514 :                 scope->space[t] = scope->space[t]->peer;
     373         514 :                 freeSymbol(prg);
     374             :         } else {
     375             :                 Symbol nxt = scope->space[t];
     376          69 :                 while (nxt->peer != NULL) {
     377          69 :                         if (nxt->peer == prg) {
     378          35 :                                 nxt->peer = prg->peer;
     379          35 :                                 nxt->skip = prg->peer;
     380          35 :                                 freeSymbol(prg);
     381          35 :                                 return;
     382             :                         }
     383             :                         nxt = nxt->peer;
     384             :                 }
     385             :         }
     386             : }
     387             : 
     388             : /*
     389             :  * Searching the scope structure.
     390             :  * Finding a scope is unrestricted. For modules we explicitly look for
     391             :  * the start of a new module scope.
     392             :  * All core modules are accessed through the jumptable.
     393             :  * The 'user' module is an alias for the scope attached
     394             :  * to the current user.
     395             :  */
     396             : Module
     397    54967813 : findModule(Module scope, const char *name)
     398             : {
     399    54967813 :         Module def = scope;
     400    54967813 :         Module m;
     401    54967813 :         if (name == NULL)
     402             :                 return scope;
     403    54967813 :         m = getModule(name);
     404    54966723 :         if (m)
     405             :                 return m;
     406             : 
     407             :         /* default is always matched with current */
     408        7551 :         if (def->name == NULL)
     409             :                 return NULL;
     410             :         return def;
     411             : }
     412             : 
     413             : /*
     414             :  * The routine findSymbolInModule starts at a MAL scope level and searches
     415             :  * an element amongst the peers.
     416             :  *
     417             :  * In principal, external variables are subject to synchronization actions
     418             :  * to avoid concurrency conflicts. This also implies, that any parallel
     419             :  * block introduces a temporary scope.
     420             :  *
     421             :  * The variation on this routine is to dump the definition of
     422             :  * all matching definitions.
     423             :  */
     424             : Symbol
     425      776087 : findSymbolInModule(Module v, const char *fcn)
     426             : {
     427      776087 :         Symbol s;
     428      776087 :         if (v == NULL || fcn == NULL)
     429             :                 return NULL;
     430      776053 :         s = v->space[(int) (*fcn)];
     431     1912818 :         while (s != NULL) {
     432     1842000 :                 if (idcmp(s->name, fcn) == 0)
     433      705235 :                         return s;
     434     1136765 :                 s = s->skip;
     435             :         }
     436             :         return NULL;
     437             : }
     438             : 
     439             : Symbol
     440          91 : findSymbol(Module usermodule, const char *mod, const char *fcn)
     441             : {
     442          91 :         Module m = findModule(usermodule, mod);
     443          91 :         return findSymbolInModule(m, fcn);
     444             : }

Generated by: LCOV version 1.14