LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_module.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 153 194 78.9 %
Date: 2025-03-25 20:06:35 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, 2025 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      204151 :                         for (int j = 0; j < MAXSCOPE; j++) {
      46      203359 :                                 Symbol s;
      47      203359 :                                 if ((s = moduleIndex[i]->space[j]) != NULL) {
      48      120462 :                                         do {
      49      120462 :                                                 if (s->kind != FUNCTIONsymbol) {
      50      120421 :                                                         if (s->func && s->func->cname &&
      51      120421 :                                                                 strcmp(s->func->cname, cname) == 0)
      52          11 :                                                                 return s->func->imp;
      53             :                                                 } else {
      54          41 :                                                         if (s->def &&
      55          41 :                                                                 strcmp(s->def->binding, cname) == 0 &&
      56           0 :                                                                 s->def->stmt &&s->def->stmt[0] &&
      57           0 :                                                                 s->def->stmt[0]->fcn) {
      58           0 :                                                                 assert(0);
      59             :                                                                 return s->def->stmt[0]->fcn;
      60             :                                                         }
      61             :                                                 }
      62      120451 :                                         } while ((s = s->peer) != NULL);
      63             :                                 }
      64             :                         }
      65             :                 }
      66             :         }
      67             :         return NULL;
      68             : }
      69             : 
      70             : BAT *
      71           0 : getModules(void)
      72             : {
      73           0 :         BAT *b = COLnew(0, TYPE_str, 100, TRANSIENT);
      74           0 :         int i;
      75           0 :         Module s, n;
      76             : 
      77           0 :         if (!b)
      78             :                 return NULL;
      79           0 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
      80           0 :                 s = moduleIndex[i];
      81           0 :                 while (s) {
      82           0 :                         if (BUNappend(b, s->name, FALSE) != GDK_SUCCEED) {
      83           0 :                                 BBPreclaim(b);
      84           0 :                                 return NULL;
      85             :                         }
      86           0 :                         n = s->link;
      87           0 :                         while (n)
      88           0 :                                 n = n->link;
      89             :                         s = s->link;
      90             :                 }
      91             :         }
      92             :         return b;
      93             : }
      94             : 
      95             : // perform sanity check on duplicate occurrences as well
      96             : void
      97           0 : dumpModules(stream *out)
      98             : {
      99           0 :         int i;
     100           0 :         Module s, n;
     101           0 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     102           0 :                 s = moduleIndex[i];
     103           0 :                 while (s) {
     104           0 :                         mnstr_printf(out, "[%d] module %s\n", i, s->name);
     105           0 :                         n = s->link;
     106           0 :                         while (n) {
     107           0 :                                 if (n == s)
     108           0 :                                         mnstr_printf(out,
     109             :                                                                  "ASSERTION error, double occurrence of symbol in symbol table\n");
     110           0 :                                 n = n->link;
     111             :                         }
     112           0 :                         s = s->link;
     113             :                 }
     114             :         }
     115           0 : }
     116             : 
     117             : /* Remove all globally known functions */
     118             : void
     119         355 : mal_module_reset(void)
     120             : {
     121         355 :         int i;
     122         355 :         Module m;
     123             : 
     124      363875 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     125      363520 :                 m = moduleIndex[i];
     126      363520 :                 moduleIndex[i] = 0;
     127      386913 :                 while (m) {
     128       23393 :                         Module next = m->link;
     129       23393 :                         freeModule(m);
     130       23393 :                         m = next;
     131             :                 }
     132             :         }
     133         355 : }
     134             : 
     135             : static int
     136    64673271 : getModuleIndex(const char *name)
     137             : {
     138    64673271 :         return (int) (strHash(name) % MODULE_HASH_SIZE);
     139             : }
     140             : 
     141             : static void
     142       23393 : clrModuleIndex(Module cur)
     143             : {
     144       23393 :         int index = getModuleIndex(cur->name);
     145       23393 :         Module prev = NULL;
     146       23393 :         Module m = moduleIndex[index];
     147       23393 :         while (m) {
     148           0 :                 if (m == cur) {
     149           0 :                         if (!prev) {
     150           0 :                                 moduleIndex[index] = m->link;
     151             :                         } else {
     152           0 :                                 prev->link = m->link;
     153             :                         }
     154           0 :                         return;
     155             :                 }
     156           0 :                 prev = m;
     157           0 :                 m = m->link;
     158             :         }
     159             : }
     160             : 
     161             : static void
     162       23516 : addModuleToIndex(Module cur)
     163             : {
     164       23516 :         int index = getModuleIndex(cur->name);
     165       23516 :         cur->link = moduleIndex[index];
     166       23516 :         moduleIndex[index] = cur;
     167       23516 : }
     168             : 
     169             : Module
     170    64626362 : getModule(const char *name)
     171             : {
     172    64627450 :         for (Module m = moduleIndex[getModuleIndex(name)]; m; m = m->link) {
     173    64591207 :                 if (name == m->name)
     174    64590119 :                         return m;
     175             :         }
     176             :         return NULL;
     177             : }
     178             : 
     179             : void
     180          16 : getModuleList(Module **out, int *length)
     181             : {
     182          16 :         int i;
     183          16 :         int moduleCount = 0;
     184          16 :         int currentIndex = 0;
     185       16400 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     186       16384 :                 Module m = moduleIndex[i];
     187       17446 :                 while (m) {
     188        1062 :                         moduleCount++;
     189        1062 :                         m = m->link;
     190             :                 }
     191             :         }
     192          16 :         *out = GDKzalloc(moduleCount * sizeof(Module));
     193          16 :         if (*out == NULL) {
     194             :                 return;
     195             :         }
     196          16 :         *length = moduleCount;
     197             : 
     198       16400 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     199       16384 :                 Module m = moduleIndex[i];
     200       17446 :                 while (m) {
     201        1062 :                         (*out)[currentIndex++] = m;
     202        1062 :                         m = m->link;
     203             :                 }
     204             :         }
     205             : }
     206             : 
     207             : void
     208          16 : freeModuleList(Module *list)
     209             : {
     210          16 :         GDKfree(list);
     211          16 : }
     212             : 
     213             : /*
     214             :  * Module scope management
     215             :  * It will contain the symbol table of all globally accessible functions.
     216             :  */
     217             : Module
     218       23516 : globalModule(const char *nme)
     219             : {
     220       23516 :         Module cur;
     221             : 
     222             :         // Global modules are not named 'user'
     223       23516 :         assert(strcmp(nme, userRef));
     224       23516 :         nme = putName(nme);
     225       23516 :         if (nme == NULL)
     226             :                 return NULL;
     227       23516 :         cur = (Module) GDKmalloc(sizeof(ModuleRecord));
     228       23516 :         if (cur == NULL)
     229             :                 return NULL;
     230       23516 :         *cur = (ModuleRecord) {
     231             :                 .name = nme,
     232             :         };
     233       23516 :         addModuleToIndex(cur);
     234       23516 :         return cur;
     235             : }
     236             : 
     237             : /* Every client record has a private module name 'user'
     238             :  * for keeping around non-shared functions */
     239             : Module
     240       37943 : userModule(void)
     241             : {
     242       37943 :         Module cur;
     243             : 
     244       37943 :         cur = (Module) GDKmalloc(sizeof(ModuleRecord));
     245       37943 :         if (cur == NULL)
     246             :                 return NULL;
     247       37943 :         *cur = (ModuleRecord) {
     248             :                 .name = userRef,
     249             :                 .link = NULL,
     250             :         };
     251       37943 :         return cur;
     252             : }
     253             : 
     254             : /*
     255             :  * The scope can be fixed. This is used by the parser.
     256             :  * Reading a module often calls for creation first.
     257             :  */
     258             : Module
     259           8 : fixModule(const char *nme)
     260             : {
     261           8 :         Module m;
     262             : 
     263           8 :         m = getModule(nme);
     264           8 :         if (m)
     265             :                 return m;
     266           4 :         return globalModule(nme);
     267             : }
     268             : 
     269             : /*
     270             :  * The freeModule operation throws away a symbol without
     271             :  * concerns on it whereabouts in the scope structure.
     272             :  */
     273             : static void
     274       61335 : freeSubScope(Module scope)
     275             : {
     276       61335 :         int i;
     277       61335 :         Symbol s;
     278             : 
     279    15762907 :         for (i = 0; i < MAXSCOPE; i++) {
     280    15701572 :                 if (scope->space[i]) {
     281      204536 :                         s = scope->space[i];
     282      204536 :                         scope->space[i] = NULL;
     283      204536 :                         freeSymbolList(s);
     284             :                 }
     285             :         }
     286       61335 : }
     287             : 
     288             : void
     289       61335 : freeModule(Module m)
     290             : {
     291       61335 :         Symbol s;
     292             : 
     293       61335 :         if (m == NULL)
     294             :                 return;
     295       61335 :         if ((s = findSymbolInModule(m, "epilogue")) != NULL) {
     296        2463 :                 if (s->kind == COMMANDsymbol && s->func->argc <= 1 /* zero or one arg */) {
     297        2463 :                         int status = 0;
     298        2463 :                         str ret;
     299             : 
     300        2463 :                         TRC_INFO(MAL_LOADER, "Unloading module %s\n", m->name);
     301        2463 :                         ret = (*(str (*)(int *)) s->func->imp) (&status);
     302        2463 :                         freeException(ret);
     303        2463 :                         (void) status;
     304             :                 }
     305             :         }
     306       61335 :         freeSubScope(m);
     307       61335 :         if (strcmp(m->name, userRef)) {
     308       23393 :                 clrModuleIndex(m);
     309             :         }
     310       61335 :         if (m->help)
     311           0 :                 GDKfree(m->help);
     312       61335 :         GDKfree(m);
     313             : }
     314             : 
     315             : /*
     316             :  * After filling in a structure it is added to the multi-level symbol
     317             :  * table.  We keep a skip list of similarly named function symbols.
     318             :  * This speeds up searching provided the modules adhere to the
     319             :  * structure and group the functions as well.
     320             :  */
     321             : void
     322     3669920 : insertSymbol(Module scope, Symbol prg)
     323             : {
     324     3669920 :         int t;
     325             : 
     326     3669920 :         assert(scope);
     327     3669920 :         t = getSymbolIndex(prg->name);
     328     3669920 :         if (scope->space[t] != prg) {
     329     3669910 :                 prg->peer = scope->space[t];
     330     3669910 :                 scope->space[t] = prg;
     331     3669910 :                 if (prg->peer && idcmp(prg->name, prg->peer->name) == 0)
     332     3052718 :                         prg->skip = prg->peer->skip;
     333             :                 else
     334      617192 :                         prg->skip = prg->peer;
     335             :         }
     336     3669920 :         assert(prg != prg->peer);
     337     3669920 : }
     338             : 
     339             : /*
     340             :  * Removal of elements from the symbol table should be
     341             :  * done with care. For, it should be assured that
     342             :  * there are no references to the definition at the
     343             :  * moment of removal. This situation can not easily
     344             :  * checked at runtime, without tremendous overhead.
     345             :  */
     346             : void
     347         513 : deleteSymbol(Module scope, Symbol prg)
     348             : {
     349         513 :         InstrPtr sig;
     350         513 :         int t;
     351             : 
     352         513 :         sig = getSignature(prg);
     353         513 :         if (getModuleId(sig) && getModuleId(sig) != scope->name) {
     354             :                 /* move the definition to the proper place */
     355             :                 /* default scope is the last resort */
     356           0 :                 Module c = findModule(scope, getModuleId(sig));
     357           0 :                 if (c)
     358         513 :                         scope = c;
     359             :         }
     360         513 :         t = getSymbolIndex(getFunctionId(sig));
     361         513 :         if (scope->space[t] == prg) {
     362         487 :                 scope->space[t] = scope->space[t]->peer;
     363         487 :                 freeSymbol(prg);
     364             :         } else {
     365             :                 Symbol nxt = scope->space[t];
     366          50 :                 while (nxt->peer != NULL) {
     367          50 :                         if (nxt->peer == prg) {
     368          26 :                                 nxt->peer = prg->peer;
     369          26 :                                 nxt->skip = prg->peer;
     370          26 :                                 freeSymbol(prg);
     371          26 :                                 return;
     372             :                         }
     373             :                         nxt = nxt->peer;
     374             :                 }
     375             :         }
     376             : }
     377             : 
     378             : /*
     379             :  * Searching the scope structure.
     380             :  * Finding a scope is unrestricted. For modules we explicitly look for
     381             :  * the start of a new module scope.
     382             :  * All core modules are accessed through the jumptable.
     383             :  * The 'user' module is an alias for the scope attached
     384             :  * to the current user.
     385             :  */
     386             : Module
     387    60796191 : findModule(Module scope, const char *name)
     388             : {
     389    60796191 :         Module def = scope;
     390    60796191 :         Module m;
     391    60796191 :         if (name == NULL)
     392             :                 return scope;
     393    60796191 :         m = getModule(name);
     394    60795364 :         if (m)
     395             :                 return m;
     396             : 
     397             :         /* default is always matched with current */
     398        7561 :         if (def->name == NULL)
     399             :                 return NULL;
     400             :         return def;
     401             : }
     402             : 
     403             : /*
     404             :  * The routine findSymbolInModule starts at a MAL scope level and searches
     405             :  * an element amongst the peers.
     406             :  *
     407             :  * In principal, external variables are subject to synchronization actions
     408             :  * to avoid concurrency conflicts. This also implies, that any parallel
     409             :  * block introduces a temporary scope.
     410             :  *
     411             :  * The variation on this routine is to dump the definition of
     412             :  * all matching definitions.
     413             :  */
     414             : Symbol
     415      662670 : findSymbolInModule(Module v, const char *fcn)
     416             : {
     417      662670 :         Symbol s;
     418      662670 :         if (v == NULL || fcn == NULL)
     419             :                 return NULL;
     420      662653 :         s = v->space[(int) (*fcn)];
     421     1690229 :         while (s != NULL) {
     422     1618739 :                 if (idcmp(s->name, fcn) == 0)
     423      591163 :                         return s;
     424     1027576 :                 s = s->skip;
     425             :         }
     426             :         return NULL;
     427             : }
     428             : 
     429             : Symbol
     430          91 : findSymbol(Module usermodule, const char *mod, const char *fcn)
     431             : {
     432          91 :         Module m = findModule(usermodule, mod);
     433          91 :         return findSymbolInModule(m, fcn);
     434             : }

Generated by: LCOV version 1.14