LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_module.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 155 196 79.1 %
Date: 2024-12-19 23:10:26 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      201324 :                         for (int j = 0; j < MAXSCOPE; j++) {
      46      200543 :                                 Symbol s;
      47      200543 :                                 if ((s = moduleIndex[i]->space[j]) != NULL) {
      48      120440 :                                         do {
      49      120440 :                                                 if (s->kind != FUNCTIONsymbol) {
      50      120399 :                                                         if (s->func && s->func->cname &&
      51      120399 :                                                                 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      120429 :                                         } 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         350 : mal_module_reset(void)
     120             : {
     121         350 :         int i;
     122         350 :         Module m;
     123             : 
     124      358750 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     125      358400 :                 m = moduleIndex[i];
     126      358400 :                 moduleIndex[i] = 0;
     127      381123 :                 while (m) {
     128       22723 :                         Module next = m->link;
     129       22723 :                         freeModule(m);
     130       22723 :                         m = next;
     131             :                 }
     132             :         }
     133         350 : }
     134             : 
     135             : static int
     136    78716745 : getModuleIndex(const char *name)
     137             : {
     138    78716745 :         return (int) (strHash(name) % MODULE_HASH_SIZE);
     139             : }
     140             : 
     141             : static void
     142       22723 : clrModuleIndex(Module cur)
     143             : {
     144       22723 :         int index = getModuleIndex(cur->name);
     145       22723 :         Module prev = NULL;
     146       22723 :         Module m = moduleIndex[index];
     147       22723 :         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       22845 : addModuleToIndex(Module cur)
     163             : {
     164       22845 :         int index = getModuleIndex(cur->name);
     165       22845 :         cur->link = moduleIndex[index];
     166       22845 :         moduleIndex[index] = cur;
     167       22845 : }
     168             : 
     169             : Module
     170    78671177 : getModule(const char *name)
     171             : {
     172    78671177 :         int index = getModuleIndex(name);
     173    78671177 :         Module m = moduleIndex[index];
     174    78672250 :         while (m) {
     175    78651967 :                 if (name == m->name)
     176    78650894 :                         return m;
     177        1073 :                 m = m->link;
     178             :         }
     179             :         return NULL;
     180             : }
     181             : 
     182             : void
     183          16 : getModuleList(Module **out, int *length)
     184             : {
     185          16 :         int i;
     186          16 :         int moduleCount = 0;
     187          16 :         int currentIndex = 0;
     188       16400 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     189       16384 :                 Module m = moduleIndex[i];
     190       17430 :                 while (m) {
     191        1046 :                         moduleCount++;
     192        1046 :                         m = m->link;
     193             :                 }
     194             :         }
     195          16 :         *out = GDKzalloc(moduleCount * sizeof(Module));
     196          16 :         if (*out == NULL) {
     197             :                 return;
     198             :         }
     199          16 :         *length = moduleCount;
     200             : 
     201       16400 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     202       16384 :                 Module m = moduleIndex[i];
     203       17430 :                 while (m) {
     204        1046 :                         (*out)[currentIndex++] = m;
     205        1046 :                         m = m->link;
     206             :                 }
     207             :         }
     208             : }
     209             : 
     210             : void
     211          16 : freeModuleList(Module *list)
     212             : {
     213          16 :         GDKfree(list);
     214          16 : }
     215             : 
     216             : /*
     217             :  * Module scope management
     218             :  * It will contain the symbol table of all globally accessible functions.
     219             :  */
     220             : Module
     221       22845 : globalModule(const char *nme)
     222             : {
     223       22845 :         Module cur;
     224             : 
     225             :         // Global modules are not named 'user'
     226       22845 :         assert(strcmp(nme, userRef));
     227       22845 :         nme = putName(nme);
     228       22845 :         if (nme == NULL)
     229             :                 return NULL;
     230       22845 :         cur = (Module) GDKmalloc(sizeof(ModuleRecord));
     231       22845 :         if (cur == NULL)
     232             :                 return NULL;
     233       22845 :         *cur = (ModuleRecord) {
     234             :                 .name = nme,
     235             :         };
     236       22845 :         addModuleToIndex(cur);
     237       22845 :         return cur;
     238             : }
     239             : 
     240             : /* Every client record has a private module name 'user'
     241             :  * for keeping around non-shared functions */
     242             : Module
     243       37892 : userModule(void)
     244             : {
     245       37892 :         Module cur;
     246             : 
     247       37892 :         cur = (Module) GDKmalloc(sizeof(ModuleRecord));
     248       37891 :         if (cur == NULL)
     249             :                 return NULL;
     250       37891 :         *cur = (ModuleRecord) {
     251             :                 .name = userRef,
     252             :                 .link = NULL,
     253             :         };
     254       37891 :         return cur;
     255             : }
     256             : 
     257             : /*
     258             :  * The scope can be fixed. This is used by the parser.
     259             :  * Reading a module often calls for creation first.
     260             :  */
     261             : Module
     262           8 : fixModule(const char *nme)
     263             : {
     264           8 :         Module m;
     265             : 
     266           8 :         m = getModule(nme);
     267           8 :         if (m)
     268             :                 return m;
     269           4 :         return globalModule(nme);
     270             : }
     271             : 
     272             : /*
     273             :  * The freeModule operation throws away a symbol without
     274             :  * concerns on it whereabouts in the scope structure.
     275             :  */
     276             : static void
     277       60613 : freeSubScope(Module scope)
     278             : {
     279       60613 :         int i;
     280       60613 :         Symbol s;
     281             : 
     282    15576538 :         for (i = 0; i < MAXSCOPE; i++) {
     283    15515924 :                 if (scope->space[i]) {
     284      201451 :                         s = scope->space[i];
     285      201451 :                         scope->space[i] = NULL;
     286      201451 :                         freeSymbolList(s);
     287             :                 }
     288             :         }
     289       60614 : }
     290             : 
     291             : void
     292       60613 : freeModule(Module m)
     293             : {
     294       60613 :         Symbol s;
     295             : 
     296       60613 :         if (m == NULL)
     297             :                 return;
     298       60613 :         if ((s = findSymbolInModule(m, "epilogue")) != NULL) {
     299        2088 :                 if (s->kind == COMMANDsymbol && s->func->argc <= 1 /* zero or one arg */) {
     300        2088 :                         int status = 0;
     301        2088 :                         str ret = MAL_SUCCEED;
     302             : 
     303        2088 :                         ret = (*(str (*)(int *)) s->func->imp) (&status);
     304        2088 :                         freeException(ret);
     305        2088 :                         (void) status;
     306             :                 }
     307             :         }
     308       60613 :         freeSubScope(m);
     309       60614 :         if (strcmp(m->name, userRef)) {
     310       22723 :                 clrModuleIndex(m);
     311             :         }
     312       60614 :         if (m->help)
     313           0 :                 GDKfree(m->help);
     314       60614 :         GDKfree(m);
     315             : }
     316             : 
     317             : /*
     318             :  * After filling in a structure it is added to the multi-level symbol
     319             :  * table.  We keep a skip list of similarly named function symbols.
     320             :  * This speeds up searching provided the modules adhere to the
     321             :  * structure and group the functions as well.
     322             :  */
     323             : void
     324     3618229 : insertSymbol(Module scope, Symbol prg)
     325             : {
     326     3618229 :         int t;
     327             : 
     328     3618229 :         assert(scope);
     329     3618229 :         t = getSymbolIndex(prg->name);
     330     3618229 :         if (scope->space[t] != prg) {
     331     3618219 :                 prg->peer = scope->space[t];
     332     3618219 :                 scope->space[t] = prg;
     333     3618219 :                 if (prg->peer && idcmp(prg->name, prg->peer->name) == 0)
     334     3009567 :                         prg->skip = prg->peer->skip;
     335             :                 else
     336      608652 :                         prg->skip = prg->peer;
     337             :         }
     338     3618229 :         assert(prg != prg->peer);
     339     3618229 : }
     340             : 
     341             : /*
     342             :  * Removal of elements from the symbol table should be
     343             :  * done with care. For, it should be assured that
     344             :  * there are no references to the definition at the
     345             :  * moment of removal. This situation can not easily
     346             :  * checked at runtime, without tremendous overhead.
     347             :  */
     348             : void
     349         515 : deleteSymbol(Module scope, Symbol prg)
     350             : {
     351         515 :         InstrPtr sig;
     352         515 :         int t;
     353             : 
     354         515 :         sig = getSignature(prg);
     355         515 :         if (getModuleId(sig) && getModuleId(sig) != scope->name) {
     356             :                 /* move the definition to the proper place */
     357             :                 /* default scope is the last resort */
     358           0 :                 Module c = findModule(scope, getModuleId(sig));
     359           0 :                 if (c)
     360         515 :                         scope = c;
     361             :         }
     362         515 :         t = getSymbolIndex(getFunctionId(sig));
     363         515 :         if (scope->space[t] == prg) {
     364         489 :                 scope->space[t] = scope->space[t]->peer;
     365         489 :                 freeSymbol(prg);
     366             :         } else {
     367             :                 Symbol nxt = scope->space[t];
     368          50 :                 while (nxt->peer != NULL) {
     369          50 :                         if (nxt->peer == prg) {
     370          26 :                                 nxt->peer = prg->peer;
     371          26 :                                 nxt->skip = prg->peer;
     372          26 :                                 freeSymbol(prg);
     373          26 :                                 return;
     374             :                         }
     375             :                         nxt = nxt->peer;
     376             :                 }
     377             :         }
     378             : }
     379             : 
     380             : /*
     381             :  * Searching the scope structure.
     382             :  * Finding a scope is unrestricted. For modules we explicitly look for
     383             :  * the start of a new module scope.
     384             :  * All core modules are accessed through the jumptable.
     385             :  * The 'user' module is an alias for the scope attached
     386             :  * to the current user.
     387             :  */
     388             : Module
     389    74926739 : findModule(Module scope, const char *name)
     390             : {
     391    74926739 :         Module def = scope;
     392    74926739 :         Module m;
     393    74926739 :         if (name == NULL)
     394             :                 return scope;
     395    74926739 :         m = getModule(name);
     396    74943520 :         if (m)
     397             :                 return m;
     398             : 
     399             :         /* default is always matched with current */
     400        7564 :         if (def->name == NULL)
     401             :                 return NULL;
     402             :         return def;
     403             : }
     404             : 
     405             : /*
     406             :  * The routine findSymbolInModule starts at a MAL scope level and searches
     407             :  * an element amongst the peers.
     408             :  *
     409             :  * In principal, external variables are subject to synchronization actions
     410             :  * to avoid concurrency conflicts. This also implies, that any parallel
     411             :  * block introduces a temporary scope.
     412             :  *
     413             :  * The variation on this routine is to dump the definition of
     414             :  * all matching definitions.
     415             :  */
     416             : Symbol
     417      621860 : findSymbolInModule(Module v, const char *fcn)
     418             : {
     419      621860 :         Symbol s;
     420      621860 :         if (v == NULL || fcn == NULL)
     421             :                 return NULL;
     422      621843 :         s = v->space[(int) (*fcn)];
     423     1622892 :         while (s != NULL) {
     424     1551921 :                 if (idcmp(s->name, fcn) == 0)
     425      550872 :                         return s;
     426     1001049 :                 s = s->skip;
     427             :         }
     428             :         return NULL;
     429             : }
     430             : 
     431             : Symbol
     432          91 : findSymbol(Module usermodule, const char *mod, const char *fcn)
     433             : {
     434          91 :         Module m = findModule(usermodule, mod);
     435          91 :         return findSymbolInModule(m, fcn);
     436             : }

Generated by: LCOV version 1.14