LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_module.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 158 201 78.6 %
Date: 2024-10-04 20:04:04 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      120832 :                                         do {
      49      120832 :                                                 if (s->kind != FUNCTIONsymbol) {
      50      120791 :                                                         if (s->func && s->func->cname &&
      51      120791 :                                                                 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      120821 :                                         } 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         328 : mal_module_reset(void)
     120             : {
     121         328 :         int i;
     122         328 :         Module m;
     123             : 
     124      336200 :         for (i = 0; i < MODULE_HASH_SIZE; i++) {
     125      335872 :                 m = moduleIndex[i];
     126      335872 :                 moduleIndex[i] = 0;
     127      358149 :                 while (m) {
     128       22277 :                         Module next = m->link;
     129       22277 :                         freeModule(m);
     130       22277 :                         m = next;
     131             :                 }
     132             :         }
     133         328 : }
     134             : 
     135             : static int
     136    61065503 : getModuleIndex(const char *name)
     137             : {
     138    61065503 :         return (int) (strHash(name) % MODULE_HASH_SIZE);
     139             : }
     140             : 
     141             : static void
     142       22277 : clrModuleIndex(Module cur)
     143             : {
     144       22277 :         int index = getModuleIndex(cur->name);
     145       22277 :         Module prev = NULL;
     146       22277 :         Module m = moduleIndex[index];
     147       22277 :         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       22405 : addModuleToIndex(Module cur)
     163             : {
     164       22405 :         int index = getModuleIndex(cur->name);
     165       22405 :         cur->link = moduleIndex[index];
     166       22405 :         moduleIndex[index] = cur;
     167       22405 : }
     168             : 
     169             : Module
     170    61020821 : getModule(const char *name)
     171             : {
     172    61020821 :         int index = getModuleIndex(name);
     173    61020821 :         Module m = moduleIndex[index];
     174    61021828 :         while (m) {
     175    60984716 :                 if (name == m->name)
     176    60983709 :                         return m;
     177        1007 :                 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       17478 :                 while (m) {
     191        1094 :                         moduleCount++;
     192        1094 :                         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       17478 :                 while (m) {
     204        1094 :                         (*out)[currentIndex++] = m;
     205        1094 :                         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       22405 : globalModule(const char *nme)
     222             : {
     223       22405 :         Module cur;
     224             : 
     225             :         // Global modules are not named 'user'
     226       22405 :         assert(strcmp(nme, "user"));
     227       22405 :         nme = putName(nme);
     228       22405 :         if (nme == NULL)
     229             :                 return NULL;
     230       22405 :         cur = (Module) GDKzalloc(sizeof(ModuleRecord));
     231       22405 :         if (cur == NULL)
     232             :                 return NULL;
     233       22405 :         cur->name = nme;
     234       22405 :         cur->link = NULL;
     235       22405 :         addModuleToIndex(cur);
     236       22405 :         return cur;
     237             : }
     238             : 
     239             : /* Every client record has a private module name 'user'
     240             :  * for keeping around non-shared functions */
     241             : Module
     242       38829 : userModule(void)
     243             : {
     244       38829 :         Module cur;
     245             : 
     246       38829 :         cur = (Module) GDKzalloc(sizeof(ModuleRecord));
     247       38829 :         if (cur == NULL)
     248             :                 return NULL;
     249       38829 :         cur->name = putName("user");
     250       38829 :         if (cur->name == NULL) {
     251           0 :                 GDKfree(cur);
     252           0 :                 return NULL;
     253             :         }
     254       38829 :         cur->link = NULL;
     255       38829 :         return cur;
     256             : }
     257             : 
     258             : /*
     259             :  * The scope can be fixed. This is used by the parser.
     260             :  * Reading a module often calls for creation first.
     261             :  */
     262             : Module
     263           8 : fixModule(const char *nme)
     264             : {
     265           8 :         Module m;
     266             : 
     267           8 :         m = getModule(nme);
     268           8 :         if (m)
     269             :                 return m;
     270           4 :         return globalModule(nme);
     271             : }
     272             : 
     273             : /*
     274             :  * The freeModule operation throws away a symbol without
     275             :  * concerns on it whereabouts in the scope structure.
     276             :  */
     277             : static void
     278       61105 : freeSubScope(Module scope)
     279             : {
     280       61105 :         int i;
     281       61105 :         Symbol s;
     282             : 
     283    15703261 :         for (i = 0; i < MAXSCOPE; i++) {
     284    15642156 :                 if (scope->space[i]) {
     285      198325 :                         s = scope->space[i];
     286      198325 :                         scope->space[i] = NULL;
     287      198325 :                         freeSymbolList(s);
     288             :                 }
     289             :         }
     290       61105 : }
     291             : 
     292             : void
     293       61105 : freeModule(Module m)
     294             : {
     295       61105 :         Symbol s;
     296             : 
     297       61105 :         if (m == NULL)
     298             :                 return;
     299       61105 :         if ((s = findSymbolInModule(m, "epilogue")) != NULL) {
     300        1956 :                 if (s->kind == COMMANDsymbol && s->func->argc <= 1 /* zero or one arg */) {
     301        1956 :                         int status = 0;
     302        1956 :                         str ret = MAL_SUCCEED;
     303             : 
     304        1956 :                         ret = (*(str (*)(int *)) s->func->imp) (&status);
     305        1956 :                         freeException(ret);
     306        1956 :                         (void) status;
     307             :                 }
     308             :         }
     309       61105 :         freeSubScope(m);
     310       61105 :         if (strcmp(m->name, "user")) {
     311       22277 :                 clrModuleIndex(m);
     312             :         }
     313       61105 :         if (m->help)
     314           0 :                 GDKfree(m->help);
     315       61105 :         GDKfree(m);
     316             : }
     317             : 
     318             : /*
     319             :  * After filling in a structure it is added to the multi-level symbol
     320             :  * table.  We keep a skip list of similarly named function symbols.
     321             :  * This speeds up searching provided the modules adhere to the
     322             :  * structure and group the functions as well.
     323             :  */
     324             : void
     325     3406539 : insertSymbol(Module scope, Symbol prg)
     326             : {
     327     3406539 :         int t;
     328             : 
     329     3406539 :         assert(scope);
     330     3406539 :         t = getSymbolIndex(prg->name);
     331     3406539 :         if (scope->space[t] != prg) {
     332     3406529 :                 prg->peer = scope->space[t];
     333     3406529 :                 scope->space[t] = prg;
     334     3406529 :                 if (prg->peer && idcmp(prg->name, prg->peer->name) == 0)
     335     2822807 :                         prg->skip = prg->peer->skip;
     336             :                 else
     337      583722 :                         prg->skip = prg->peer;
     338             :         }
     339     3406539 :         assert(prg != prg->peer);
     340     3406539 : }
     341             : 
     342             : /*
     343             :  * Removal of elements from the symbol table should be
     344             :  * done with care. For, it should be assured that
     345             :  * there are no references to the definition at the
     346             :  * moment of removal. This situation can not easily
     347             :  * checked at runtime, without tremendous overhead.
     348             :  */
     349             : void
     350         515 : deleteSymbol(Module scope, Symbol prg)
     351             : {
     352         515 :         InstrPtr sig;
     353         515 :         int t;
     354             : 
     355         515 :         sig = getSignature(prg);
     356         515 :         if (getModuleId(sig) && getModuleId(sig) != scope->name) {
     357             :                 /* move the definition to the proper place */
     358             :                 /* default scope is the last resort */
     359           0 :                 Module c = findModule(scope, getModuleId(sig));
     360           0 :                 if (c)
     361         515 :                         scope = c;
     362             :         }
     363         515 :         t = getSymbolIndex(getFunctionId(sig));
     364         515 :         if (scope->space[t] == prg) {
     365         489 :                 scope->space[t] = scope->space[t]->peer;
     366         489 :                 freeSymbol(prg);
     367             :         } else {
     368             :                 Symbol nxt = scope->space[t];
     369          50 :                 while (nxt->peer != NULL) {
     370          50 :                         if (nxt->peer == prg) {
     371          26 :                                 nxt->peer = prg->peer;
     372          26 :                                 nxt->skip = prg->peer;
     373          26 :                                 freeSymbol(prg);
     374          26 :                                 return;
     375             :                         }
     376             :                         nxt = nxt->peer;
     377             :                 }
     378             :         }
     379             : }
     380             : 
     381             : /*
     382             :  * Searching the scope structure.
     383             :  * Finding a scope is unrestricted. For modules we explicitly look for
     384             :  * the start of a new module scope.
     385             :  * All core modules are accessed through the jumptable.
     386             :  * The 'user' module is an alias for the scope attached
     387             :  * to the current user.
     388             :  */
     389             : Module
     390    57490474 : findModule(Module scope, const char *name)
     391             : {
     392    57490474 :         Module def = scope;
     393    57490474 :         Module m;
     394    57490474 :         if (name == NULL)
     395             :                 return scope;
     396    57490474 :         m = getModule(name);
     397    57488125 :         if (m)
     398             :                 return m;
     399             : 
     400             :         /* default is always matched with current */
     401        7541 :         if (def->name == NULL)
     402             :                 return NULL;
     403             :         return def;
     404             : }
     405             : 
     406             : /*
     407             :  * The routine findSymbolInModule starts at a MAL scope level and searches
     408             :  * an element amongst the peers.
     409             :  *
     410             :  * In principal, external variables are subject to synchronization actions
     411             :  * to avoid concurrency conflicts. This also implies, that any parallel
     412             :  * block introduces a temporary scope.
     413             :  *
     414             :  * The variation on this routine is to dump the definition of
     415             :  * all matching definitions.
     416             :  */
     417             : Symbol
     418      602192 : findSymbolInModule(Module v, const char *fcn)
     419             : {
     420      602192 :         Symbol s;
     421      602192 :         if (v == NULL || fcn == NULL)
     422             :                 return NULL;
     423      602175 :         s = v->space[(int) (*fcn)];
     424     1563682 :         while (s != NULL) {
     425     1492527 :                 if (idcmp(s->name, fcn) == 0)
     426      531020 :                         return s;
     427      961507 :                 s = s->skip;
     428             :         }
     429             :         return NULL;
     430             : }
     431             : 
     432             : Symbol
     433          91 : findSymbol(Module usermodule, const char *mod, const char *fcn)
     434             : {
     435          91 :         Module m = findModule(usermodule, mod);
     436          91 :         return findSymbolInModule(m, fcn);
     437             : }

Generated by: LCOV version 1.14