Browse Source

ncd: NCDModule: allow separating static module information from generated at runtime by the interpreter. Fix other stuff to work with
the new design. This allows modules to keep interpreter-wide state, and, when modules are fixed, will allow running more than one
NCDInterpreter in the same program.

ambrop7 13 năm trước cách đây
mục cha
commit
8ec7e1e67d

+ 2 - 2
ncd/NCDInterpProcess.c

@@ -357,7 +357,7 @@ void NCDInterpProcess_StatementObjNames (NCDInterpProcess *o, int i, const NCD_s
     *out_num_objnames = o->stmts[i].num_objnames;
 }
 
-const struct NCDModule * NCDInterpProcess_StatementGetSimpleModule (NCDInterpProcess *o, int i)
+const struct NCDInterpModule * NCDInterpProcess_StatementGetSimpleModule (NCDInterpProcess *o, int i)
 {
     DebugObject_Access(&o->d_obj);
     ASSERT(i >= 0)
@@ -367,7 +367,7 @@ const struct NCDModule * NCDInterpProcess_StatementGetSimpleModule (NCDInterpPro
     return o->stmts[i].binding.simple_module;
 }
 
-const struct NCDModule * NCDInterpProcess_StatementGetMethodModule (NCDInterpProcess *o, int i, NCD_string_id_t obj_type, NCDModuleIndex *module_index)
+const struct NCDInterpModule * NCDInterpProcess_StatementGetMethodModule (NCDInterpProcess *o, int i, NCD_string_id_t obj_type, NCDModuleIndex *module_index)
 {
     DebugObject_Access(&o->d_obj);
     ASSERT(i >= 0)

+ 3 - 3
ncd/NCDInterpProcess.h

@@ -47,7 +47,7 @@ struct NCDInterpProcess__stmt {
     NCD_string_id_t *objnames;
     size_t num_objnames;
     union {
-        const struct NCDModule *simple_module;
+        const struct NCDInterpModule *simple_module;
         int method_name_id;
     } binding;
     NCDValMem arg_mem;
@@ -84,8 +84,8 @@ void NCDInterpProcess_Free (NCDInterpProcess *o);
 int NCDInterpProcess_FindStatement (NCDInterpProcess *o, int from_index, NCD_string_id_t name);
 const char * NCDInterpProcess_StatementCmdName (NCDInterpProcess *o, int i, NCDStringIndex *string_index);
 void NCDInterpProcess_StatementObjNames (NCDInterpProcess *o, int i, const NCD_string_id_t **out_objnames, size_t *out_num_objnames);
-const struct NCDModule * NCDInterpProcess_StatementGetSimpleModule (NCDInterpProcess *o, int i);
-const struct NCDModule * NCDInterpProcess_StatementGetMethodModule (NCDInterpProcess *o, int i, NCD_string_id_t obj_type, NCDModuleIndex *module_index);
+const struct NCDInterpModule * NCDInterpProcess_StatementGetSimpleModule (NCDInterpProcess *o, int i);
+const struct NCDInterpModule * NCDInterpProcess_StatementGetMethodModule (NCDInterpProcess *o, int i, NCD_string_id_t obj_type, NCDModuleIndex *module_index);
 int NCDInterpProcess_CopyStatementArgs (NCDInterpProcess *o, int i, NCDValMem *out_valmem, NCDValRef *out_val, NCDValReplaceProg *out_prog) WARN_UNUSED;
 void NCDInterpProcess_StatementBumpAllocSize (NCDInterpProcess *o, int i, int alloc_size);
 int NCDInterpProcess_PreallocSize (NCDInterpProcess *o);

+ 2 - 2
ncd/NCDInterpreter.c

@@ -840,7 +840,7 @@ void process_advance (struct process *p)
     STATEMENT_LOG(ps, BLOG_INFO, "initializing");
     
     // need to determine the module and object to use it on (if it's a method)
-    const struct NCDModule *module;
+    const struct NCDInterpModule *module;
     void *method_context = NULL;
     
     // get object names, e.g. "my.cat" in "my.cat->meow();"
@@ -901,7 +901,7 @@ void process_advance (struct process *p)
     }
     
     // allocate memory
-    if (!statement_allocate_memory(ps, module->alloc_size)) {
+    if (!statement_allocate_memory(ps, module->module.alloc_size)) {
         STATEMENT_LOG(ps, BLOG_ERROR, "failed to allocate memory");
         goto fail1;
     }

+ 3 - 3
ncd/NCDMethodIndex.c

@@ -168,13 +168,13 @@ void NCDMethodIndex_Free (NCDMethodIndex *o)
     NamesArray_Free(o);
 }
 
-int NCDMethodIndex_AddMethod (NCDMethodIndex *o, const char *obj_type, const char *method_name, const struct NCDModule *module)
+int NCDMethodIndex_AddMethod (NCDMethodIndex *o, const char *obj_type, size_t obj_type_len, const char *method_name, const struct NCDInterpModule *module)
 {
     ASSERT(obj_type)
     ASSERT(method_name)
     ASSERT(module)
     
-    NCD_string_id_t obj_type_id = NCDStringIndex_Get(o->string_index, obj_type);
+    NCD_string_id_t obj_type_id = NCDStringIndex_GetBin(o->string_index, obj_type, obj_type_len);
     if (obj_type_id < 0) {
         BLog(BLOG_ERROR, "NCDStringIndex_Get failed");
         goto fail0;
@@ -249,7 +249,7 @@ int NCDMethodIndex_GetMethodNameId (NCDMethodIndex *o, const char *method_name)
     return first_entry_idx;
 }
 
-const struct NCDModule * NCDMethodIndex_GetMethodModule (NCDMethodIndex *o, NCD_string_id_t obj_type, int method_name_id)
+const struct NCDInterpModule * NCDMethodIndex_GetMethodModule (NCDMethodIndex *o, NCD_string_id_t obj_type, int method_name_id)
 {
     ASSERT(obj_type >= 0)
     ASSERT(method_name_id >= 0)

+ 6 - 5
ncd/NCDMethodIndex.h

@@ -46,7 +46,7 @@ struct NCDMethodIndex__method_name {
 
 struct NCDMethodIndex__entry {
     NCD_string_id_t obj_type;
-    const struct NCDModule *module;
+    const struct NCDInterpModule *module;
     int next;
 };
 
@@ -59,7 +59,7 @@ typedef struct NCDMethodIndex__method_name *NCDMethodIndex__hasharg;
 
 /**
  * The method index associates (object_type, method_name) pairs to pointers
- * to corresponding \link NCDModule structures (whose type strings would
+ * to corresponding \link NCDInterpModule structures (whose type strings would
  * be "object_type::method_name").
  * More precisely, the method names are represented as indices into an
  * internal array, which allows very efficient lookup when the method names
@@ -93,13 +93,14 @@ void NCDMethodIndex_Free (NCDMethodIndex *o);
  * Duplicate methods will not be detected here.
  * 
  * @param obj_type object type of method, e.g. "cat" in "cat::meow".
- *                 Must not be NULL.
+ *                 Must not be NULL. Does not have to be null-terminated.
+ * @param obj_type_len number of characters in obj_type
  * @param method_name name of method, e.g. "meow" in "cat::meow".
  *                    Must not be NULL.
  * @param module pointer to module structure. Must not be NULL.
  * @return on success, a non-negative identifier; on failure, -1
  */
-int NCDMethodIndex_AddMethod (NCDMethodIndex *o, const char *obj_type, const char *method_name, const struct NCDModule *module);
+int NCDMethodIndex_AddMethod (NCDMethodIndex *o, const char *obj_type, size_t obj_type_len, const char *method_name, const struct NCDInterpModule *module);
 
 /**
  * Removes a method from the index.
@@ -129,6 +130,6 @@ int NCDMethodIndex_GetMethodNameId (NCDMethodIndex *o, const char *method_name);
  *                       by a successfull call of \link NCDMethodIndex_GetMethodNameId.
  * @return module pointer, or NULL if no such method exists
  */
-const struct NCDModule * NCDMethodIndex_GetMethodModule (NCDMethodIndex *o, NCD_string_id_t obj_type, int method_name_id);
+const struct NCDInterpModule * NCDMethodIndex_GetMethodModule (NCDMethodIndex *o, NCD_string_id_t obj_type, int method_name_id);
 
 #endif

+ 17 - 16
ncd/NCDModule.c

@@ -73,12 +73,13 @@ static void set_process_state (NCDModuleProcess *p, int state)
 #endif
 }
 
-void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, void *method_context, NCDValRef args, const struct NCDModuleInst_params *params)
+void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDInterpModule *m, void *method_context, NCDValRef args, const struct NCDModuleInst_params *params)
 {
     ASSERT(m)
-    ASSERT(m->func_new2)
-    ASSERT(m->alloc_size >= 0)
+    ASSERT(m->module.func_new2)
+    ASSERT(m->module.alloc_size >= 0)
     ASSERT(m->base_type_id >= 0)
+    ASSERT(m->group)
     ASSERT(n->mem)
     ASSERT(NCDVal_IsList(args))
     ASSERT(params)
@@ -107,7 +108,7 @@ void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, void *meth
     new_params.method_user = method_context;
     new_params.args = args;
     
-    n->m->func_new2(n->mem, n, &new_params);
+    n->m->module.func_new2(n->mem, n, &new_params);
 }
 
 void NCDModuleInst_Free (NCDModuleInst *n)
@@ -123,12 +124,12 @@ void NCDModuleInst_Die (NCDModuleInst *n)
     
     n->state = STATE_DYING;
     
-    if (!n->m->func_die) {
+    if (!n->m->module.func_die) {
         NCDModuleInst_Backend_Dead(n);
         return;
     }
     
-    n->m->func_die(n->mem);
+    n->m->module.func_die(n->mem);
     return;
 }
 
@@ -137,7 +138,7 @@ int NCDModuleInst_TryFree (NCDModuleInst *n)
     DebugObject_Access(&n->d_obj);
     ASSERT(n->state == STATE_UP || n->state == STATE_DOWN_CLEAN || n->state == STATE_DOWN_UNCLEAN)
     
-    if (n->m->func_die) {
+    if (n->m->module.func_die) {
         return 0;
     }
     
@@ -154,8 +155,8 @@ void NCDModuleInst_Clean (NCDModuleInst *n)
     if (n->state == STATE_DOWN_UNCLEAN) {
         n->state = STATE_DOWN_CLEAN;
             
-        if (n->m->func_clean) {
-            n->m->func_clean(n->mem);
+        if (n->m->module.func_clean) {
+            n->m->module.func_clean(n->mem);
             return;
         }
     }
@@ -188,7 +189,7 @@ static int can_resolve (NCDModuleInst *n)
             return 1;
         case STATE_DOWN_CLEAN:
         case STATE_DOWN_UNCLEAN:
-            return !!(n->m->flags & NCDMODULE_FLAG_CAN_RESOLVE_WHEN_DOWN);
+            return !!(n->m->module.flags & NCDMODULE_FLAG_CAN_RESOLVE_WHEN_DOWN);
         default:
             return 0;
     }
@@ -199,19 +200,19 @@ static int object_func_getvar (const NCDObject *obj, NCD_string_id_t name, NCDVa
     NCDModuleInst *n = NCDObject_DataPtr(obj);
     DebugObject_Access(&n->d_obj);
     
-    if ((!n->m->func_getvar && !n->m->func_getvar2) || !can_resolve(n)) {
+    if ((!n->m->module.func_getvar && !n->m->module.func_getvar2) || !can_resolve(n)) {
         return 0;
     }
     
     int res;
-    if (n->m->func_getvar2) {
-        res = n->m->func_getvar2(n->mem, name, mem, out_value);
+    if (n->m->module.func_getvar2) {
+        res = n->m->module.func_getvar2(n->mem, name, mem, out_value);
     } else {
         if (NCDStringIndex_HasNulls(n->params->iparams->string_index, name)) {
             return 0;
         }
         const char *name_str = NCDStringIndex_Value(n->params->iparams->string_index, name);
-        res = n->m->func_getvar(n->mem, name_str, mem, out_value);
+        res = n->m->module.func_getvar(n->mem, name_str, mem, out_value);
     }
     ASSERT(res == 0 || res == 1)
     ASSERT(res == 0 || (NCDVal_Assert(*out_value), 1))
@@ -224,11 +225,11 @@ static int object_func_getobj (const NCDObject *obj, NCD_string_id_t name, NCDOb
     NCDModuleInst *n = NCDObject_DataPtr(obj);
     DebugObject_Access(&n->d_obj);
     
-    if (!n->m->func_getobj || !can_resolve(n)) {
+    if (!n->m->module.func_getobj || !can_resolve(n)) {
         return 0;
     }
     
-    int res = n->m->func_getobj(n->mem, name, out_object);
+    int res = n->m->module.func_getobj(n->mem, name, out_object);
     ASSERT(res == 0 || res == 1)
     
     return res;

+ 63 - 21
ncd/NCDModule.h

@@ -56,6 +56,8 @@
 
 struct NCDModuleInst_s;
 struct NCDModuleProcess_s;
+struct NCDInterpModule;
+struct NCDInterpModuleGroup;
 
 /**
  * Function called to inform the interpeter of state changes of the
@@ -352,7 +354,7 @@ struct NCDModuleInst_iparams {
  * specified in a {@link NCDModule}.
  */
 typedef struct NCDModuleInst_s {
-    const struct NCDModule *m;
+    const struct NCDInterpModule *m;
     const struct NCDModuleInst_params *params;
     void *mem; // not modified by NCDModuleInst (but passed to module)
     unsigned int state:3;
@@ -394,7 +396,8 @@ typedef struct NCDModuleProcess_s {
  * can use it as outside the lifetime of NCDModuleInst.
  * 
  * @param n the instance
- * @param m structure of module functions implementing the module backend
+ * @param m pointer to the {@link NCDInterpModule} structure representing the module
+ *          to be instantiated
  * @param method_context a context pointer passed to the module backend, applicable to method-like
  *                       statements only. This should be set to the 'user' member of the
  *                       {@link NCDObject} which represents the base object for the method.
@@ -405,7 +408,7 @@ typedef struct NCDModuleProcess_s {
  * @param user argument to callback functions
  * @param params more parameters, see {@link NCDModuleInst_params}
  */
-void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, void *method_context, NCDValRef args, const struct NCDModuleInst_params *params);
+void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDInterpModule *m, void *method_context, NCDValRef args, const struct NCDModuleInst_params *params);
 
 /**
  * Frees the instance.
@@ -722,14 +725,14 @@ int NCDModuleProcess_Interp_GetSpecialObj (NCDModuleProcess *o, NCD_string_id_t
  *               {@link BReactor}, {@link BProcessManager} and {@link NCDUdevManager}.
  * @return 1 on success, 0 on failure
  */
-typedef int (*NCDModule_func_globalinit) (const struct NCDModuleInst_iparams *params);
+typedef int (*NCDModule_func_globalinit) (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params);
 
 /**
  * Function called to clean up after {@link NCDModule_func_globalinit} and modules
  * in a module group.
  * There are no backend instances alive from this module group.
  */ 
-typedef void (*NCDModule_func_globalfree) (void);
+typedef void (*NCDModule_func_globalfree) (struct NCDInterpModuleGroup *group);
 
 /**
  * Handler called to create an new module backend instance.
@@ -881,13 +884,6 @@ struct NCDModule {
      * argument to {@link NCDModule_func_new2} and other calls.
      */
     int alloc_size;
-    
-    /**
-     * The string identifier of this module's base_type (or type if base_type is
-     * not specified) according to {@link NCDStringIndex}. This is initialized
-     * by the interpreter on startup and should not be set by the module.
-     */
-    NCD_string_id_t base_type_id;
 };
 
 /**
@@ -911,18 +907,64 @@ struct NCDModuleGroup {
      * Array of module backends. The array must be terminated with a
      * structure that has a NULL type member.
      */
-    struct NCDModule *modules;
+    const struct NCDModule *modules;
+    
+    /**
+     * A pointer to an array of strings which will be mapped to
+     * {@link NCDStringIndex} string identifiers for the module to use.
+     * The array must be terminated by NULL. The resulting string
+     * identifiers will be available in the 'strings' member in
+     * {@link NCDInterpModuleGroup}.
+     */
+    const char *const*strings;
+};
+
+/**
+ * Represents an {@link NCDModule} within an interpreter.
+ * This structure is initialized by the interpreter when it loads a module group.
+ */
+struct NCDInterpModule {
+    /**
+     * A copy of the original NCDModule structure,
+     */
+    struct NCDModule module;
+    
+    /**
+     * The string identifier of this module's base_type (or type if base_type is
+     * not specified) according to {@link NCDStringIndex}.
+     */
+    NCD_string_id_t base_type_id;
+    
+    /**
+     * A pointer to the {@link NCDInterpModuleGroup} representing the group
+     * this module belongs to.
+     */
+    struct NCDInterpModuleGroup *group;
+};
+
+/**
+ * Represents an {@link NCDModuleGroup} within an interpreter.
+ * This structure is initialized by the interpreter when it loads a module group.
+ */
+struct NCDInterpModuleGroup {
+    /**
+     * A copy of the original NCDModuleGroup structure.
+     */
+    struct NCDModuleGroup group;
+    
+    /**
+     * An array of string identifiers corresponding to the strings
+     * in the 'strings' member of NCDModuleGroup. May be NULL if there
+     * are no strings in the NCDModuleGroup.
+     */
+    NCD_string_id_t *strings;
     
     /**
-     * A pointer to an array of requests for string identifiers. The 'str'
-     * member of each element of this array should be set to a string which
-     * is to be mapped to an identifier using {@link NCDStringIndex}. The
-     * array must be terminated with an element with a NULL 'str' member.
-     * The interpreter will use {@link NCDStringIndex_GetRequests} to set
-     * the corresponds 'id' members.
-     * This can be NULL if the module does not require mapping any strings.
+     * Pointer which allows the module to keep private interpreter-wide state.
+     * This can be freely modified by the module; the interpeter will not
+     * read or write it.
      */
-    struct NCD_string_request *strings;
+    void *group_state;
 };
 
 #endif

+ 104 - 91
ncd/NCDModuleIndex.c

@@ -32,6 +32,7 @@
 
 #include <misc/offset.h>
 #include <misc/balloc.h>
+#include <misc/bsize.h>
 #include <misc/hashfun.h>
 #include <misc/compare.h>
 #include <misc/substring.h>
@@ -44,22 +45,19 @@
 #include "NCDModuleIndex_mhash.h"
 #include <structure/CHash_impl.h>
 
-static int string_pointer_comparator (void *user, const char **s1, const char **s2)
+static int string_pointer_comparator (void *user, void *v1, void *v2)
 {
+    const char **s1 = v1;
+    const char **s2 = v2;
     int cmp = strcmp(*s1, *s2);
     return B_COMPARE(cmp, 0);
 }
 
 static struct NCDModuleIndex_module * find_module (NCDModuleIndex *o, const char *type)
 {
-    NCDModuleIndex__MHashRef ref = NCDModuleIndex__MHash_Lookup(&o->modules_hash, o->modules, type);
-    if (ref.link == NCDModuleIndex__MHashNullLink()) {
-        return NULL;
-    }
-    
-    ASSERT(!strcmp(ref.ptr->type, type))
-    
-    return ref.ptr;
+    NCDModuleIndex__MHashRef ref = NCDModuleIndex__MHash_Lookup(&o->modules_hash, 0, type);
+    ASSERT(!ref.link || !strcmp(ref.link->imodule.module.type, type))
+    return ref.link;
 }
 
 #ifndef NDEBUG
@@ -77,7 +75,7 @@ static struct NCDModuleIndex_base_type * find_base_type (NCDModuleIndex *o, cons
 }
 #endif
 
-static int add_method (char *type, const struct NCDModule *module, NCDMethodIndex *method_index, int *out_method_id)
+static int add_method (const char *type, const struct NCDInterpModule *module, NCDMethodIndex *method_index, int *out_method_id)
 {
     ASSERT(type)
     ASSERT(module)
@@ -100,11 +98,7 @@ static int add_method (char *type, const struct NCDModule *module, NCDMethodInde
     ASSERT(pos <= strlen(type) - search_len)
     ASSERT(!memcmp(type + pos, search, search_len))
     
-    char save = type[pos];
-    type[pos] = '\0';
-    int method_id = NCDMethodIndex_AddMethod(method_index, type, type + pos + search_len, module);
-    type[pos] = save;
-    
+    int method_id = NCDMethodIndex_AddMethod(method_index, type, pos, type + pos + search_len, module);
     if (method_id < 0) {
         BLog(BLOG_ERROR, "NCDMethodIndex_AddMethod failed");
         return 0;
@@ -118,24 +112,15 @@ int NCDModuleIndex_Init (NCDModuleIndex *o, NCDStringIndex *string_index)
 {
     ASSERT(string_index)
     
-    // allocate modules array
-    if (!(o->modules = BAllocArray(NCDMODULEINDEX_MAX_MODULES, sizeof(o->modules[0])))) {
-        BLog(BLOG_ERROR, "BAllocArray failed");
-        goto fail0;
-    }
-    
-    // set zero modules
-    o->num_modules = 0;
-    
     // init modules hash
     if (!NCDModuleIndex__MHash_Init(&o->modules_hash, NCDMODULEINDEX_MODULES_HASH_SIZE)) {
         BLog(BLOG_ERROR, "NCDModuleIndex__MHash_Init failed");
-        goto fail1;
+        goto fail0;
     }
     
 #ifndef NDEBUG
     // init base types tree
-    BAVL_Init(&o->base_types_tree, OFFSET_DIFF(struct NCDModuleIndex_base_type, base_type, base_types_tree_node), (BAVL_comparator)string_pointer_comparator, NULL);
+    BAVL_Init(&o->base_types_tree, OFFSET_DIFF(struct NCDModuleIndex_base_type, base_type, base_types_tree_node), string_pointer_comparator, NULL);
 #endif
     
     // init groups list
@@ -144,16 +129,14 @@ int NCDModuleIndex_Init (NCDModuleIndex *o, NCDStringIndex *string_index)
     // init method index
     if (!NCDMethodIndex_Init(&o->method_index, string_index)) {
         BLog(BLOG_ERROR, "NCDMethodIndex_Init failed");
-        goto fail2;
+        goto fail1;
     }
     
     DebugObject_Init(&o->d_obj);
     return 1;
     
-fail2:
-    NCDModuleIndex__MHash_Free(&o->modules_hash);
 fail1:
-    BFree(o->modules);
+    NCDModuleIndex__MHash_Free(&o->modules_hash);
 fail0:
     return 0;
 }
@@ -166,19 +149,21 @@ void NCDModuleIndex_Free (NCDModuleIndex *o)
     LinkedList0Node *ln;
     while (ln = LinkedList0_GetFirst(&o->groups_list)) {
         struct NCDModuleIndex_group *ig = UPPER_OBJECT(ln, struct NCDModuleIndex_group, groups_list_node);
-        if (ig->group->func_globalfree) {
-            ig->group->func_globalfree();
+        if (ig->igroup.group.func_globalfree) {
+            ig->igroup.group.func_globalfree(&ig->igroup);
         }
+        BFree(ig->igroup.strings);
         LinkedList0_Remove(&o->groups_list, &ig->groups_list_node);
         BFree(ig);
     }
     
 #ifndef NDEBUG
     // free base types
-    while (!BAVL_IsEmpty(&o->base_types_tree)) {
-        struct NCDModuleIndex_base_type *bt = UPPER_OBJECT(BAVL_GetFirst(&o->base_types_tree), struct NCDModuleIndex_base_type, base_types_tree_node);
+    BAVLNode *tn;
+    while (tn = BAVL_GetFirst(&o->base_types_tree)) {
+        struct NCDModuleIndex_base_type *bt = UPPER_OBJECT(tn, struct NCDModuleIndex_base_type, base_types_tree_node);
         BAVL_Remove(&o->base_types_tree, &bt->base_types_tree_node);
-        free(bt);
+        BFree(bt);
     }
 #endif
     
@@ -187,9 +172,6 @@ void NCDModuleIndex_Free (NCDModuleIndex *o)
     
     // free modules hash
     NCDModuleIndex__MHash_Free(&o->modules_hash);
-    
-    // free modules array
-    BFree(o->modules);
 }
 
 int NCDModuleIndex_AddGroup (NCDModuleIndex *o, const struct NCDModuleGroup *group, const struct NCDModuleInst_iparams *iparams, NCDStringIndex *string_index)
@@ -199,90 +181,122 @@ int NCDModuleIndex_AddGroup (NCDModuleIndex *o, const struct NCDModuleGroup *gro
     ASSERT(iparams)
     ASSERT(string_index)
     
-    struct NCDModuleIndex_group *ig = BAlloc(sizeof(*ig));
+    // count modules in the group
+    size_t num_modules = 0;
+    while (group->modules[num_modules].type) {
+        num_modules++;
+    }
+    
+    // compute allocation size
+    bsize_t size = bsize_add(bsize_fromsize(sizeof(struct NCDModuleIndex_group)), bsize_mul(bsize_fromsize(num_modules), bsize_fromsize(sizeof(struct NCDModuleIndex_module))));
+    
+    // allocate group 
+    struct NCDModuleIndex_group *ig = BAllocSize(size);
     if (!ig) {
-        BLog(BLOG_ERROR, "BAlloc failed");
+        BLog(BLOG_ERROR, "BAllocSize failed");
         goto fail0;
     }
     
-    ig->group = group;
+    // insert to groups list
     LinkedList0_Prepend(&o->groups_list, &ig->groups_list_node);
     
-    if (group->strings) {
-        if (!NCDStringIndex_GetRequests(string_index, group->strings)) {
-            BLog(BLOG_ERROR, "NCDStringIndex_GetRequests failed");
+    // copy NCDModuleGroup
+    ig->igroup.group = *group;
+    
+    if (!group->strings) {
+        // not resolving strings
+        ig->igroup.strings = NULL;
+    } else {
+        // compute number of strings
+        size_t num_strings = 0;
+        while (group->strings[num_strings]) {
+            num_strings++;
+        }
+        
+        // allocate array for string IDs
+        ig->igroup.strings = BAllocArray(num_strings, sizeof(ig->igroup.strings[0]));
+        if (!ig->igroup.strings) {
+            BLog(BLOG_ERROR, "BAllocArray failed");
             goto fail1;
         }
+        
+        // map strings to IDs
+        for (size_t i = 0; i < num_strings; i++) {
+            ig->igroup.strings[i] = NCDStringIndex_Get(string_index, group->strings[i]);
+            if (ig->igroup.strings[i] < 0) {
+                BLog(BLOG_ERROR, "NCDStringIndex_Get failed");
+                goto fail2;
+            }
+        }
     }
     
+    // call group init function
     if (group->func_globalinit) {
-        if (!group->func_globalinit(iparams)) {
+        if (!group->func_globalinit(&ig->igroup, iparams)) {
             BLog(BLOG_ERROR, "func_globalinit failed");
-            goto fail1;
+            goto fail2;
         }
     }
     
-    int num_inited_modules = 0;
+    size_t num_inited_modules = 0;
     
-    for (struct NCDModule *nm = group->modules; nm->type; nm++) {
+    // initialize modules
+    for (size_t i = 0; i < num_modules; i++) {
+        const struct NCDModule *nm = &group->modules[i];
+        struct NCDModuleIndex_module *m = &ig->modules[i];
+        
+        // make sure a module with this name doesn't exist already
         if (find_module(o, nm->type)) {
             BLog(BLOG_ERROR, "module type '%s' already exists", nm->type);
             goto loop_fail0;
         }
         
-        if (strlen(nm->type) > NCDMODULEINDEX_MAX_TYPE_LEN) {
-            BLog(BLOG_ERROR, "module type '%s' is too long (dump NCDMODULEINDEX_MAX_TYPE_LEN)", nm->type);
-            goto loop_fail0;
-        }
-        
-        if (o->num_modules == NCDMODULEINDEX_MAX_MODULES) {
-            BLog(BLOG_ERROR, "too many modules (bump NCDMODULEINDEX_MAX_MODULES)");
-            goto loop_fail0;
-        }
+        // copy NCDModule structure
+        m->imodule.module = *nm;
         
+        // determine base type
         const char *base_type = (nm->base_type ? nm->base_type : nm->type);
         ASSERT(base_type)
         
-        nm->base_type_id = NCDStringIndex_Get(string_index, base_type);
-        if (nm->base_type_id < 0) {
+        // map base type to ID
+        m->imodule.base_type_id = NCDStringIndex_Get(string_index, base_type);
+        if (m->imodule.base_type_id < 0) {
             BLog(BLOG_ERROR, "NCDStringIndex_Get failed");
             goto loop_fail0;
         }
         
-        struct NCDModuleIndex_module *m = &o->modules[o->num_modules];
+        // set group pointer
+        m->imodule.group = &ig->igroup;
         
-        strcpy(m->type, nm->type);
-        m->module = nm;
-        
-        if (!add_method(m->type, nm, &o->method_index, &m->method_id)) {
-            BLog(BLOG_ERROR, "failed to add method to method index");
+        // register method
+        if (!add_method(nm->type, &m->imodule, &o->method_index, &m->method_id)) {
             goto loop_fail0;
         }
         
 #ifndef NDEBUG
+        // ensure that this base_type does not appear in any other groups
         struct NCDModuleIndex_base_type *bt = find_base_type(o, base_type);
         if (bt) {
-            if (bt->group != group) {
+            if (bt->group != ig) {
                 BLog(BLOG_ERROR, "module base type '%s' already exists in another module group", base_type);
                 goto loop_fail1;
             }
         } else {
-            if (!(bt = malloc(sizeof(*bt)))) {
-                BLog(BLOG_ERROR, "malloc failed");
+            if (!(bt = BAlloc(sizeof(*bt)))) {
+                BLog(BLOG_ERROR, "BAlloc failed");
                 goto loop_fail1;
             }
-            
             bt->base_type = base_type;
-            bt->group = group;
+            bt->group = ig;
             ASSERT_EXECUTE(BAVL_Insert(&o->base_types_tree, &bt->base_types_tree_node, NULL))
         }
 #endif
-        
-        NCDModuleIndex__MHashRef ref = {m, o->num_modules};
-        int res = NCDModuleIndex__MHash_Insert(&o->modules_hash, o->modules, ref, NULL);
+
+        // insert to modules hash
+        NCDModuleIndex__MHashRef ref = {m, m};
+        int res = NCDModuleIndex__MHash_Insert(&o->modules_hash, 0, ref, NULL);
         ASSERT_EXECUTE(res)
         
-        o->num_modules++;
         num_inited_modules++;
         continue;
         
@@ -293,36 +307,35 @@ int NCDModuleIndex_AddGroup (NCDModuleIndex *o, const struct NCDModuleGroup *gro
         }
 #endif
     loop_fail0:
-        goto fail2;
+        goto fail3;
     }
     
     return 1;
     
-fail2:
+fail3:
     while (num_inited_modules-- > 0) {
-        o->num_modules--;
-        struct NCDModuleIndex_module *m = &o->modules[o->num_modules];
-        
-        NCDModuleIndex__MHashRef ref = {m, o->num_modules};
-        NCDModuleIndex__MHash_Remove(&o->modules_hash, o->modules, ref);
-        
+        struct NCDModuleIndex_module *m = &ig->modules[num_inited_modules];
+        NCDModuleIndex__MHashRef ref = {m, m};
+        NCDModuleIndex__MHash_Remove(&o->modules_hash, 0, ref);
 #ifndef NDEBUG
-        struct NCDModule *nm = group->modules + num_inited_modules;
-        struct NCDModuleIndex_base_type *bt = find_base_type(o, (nm->base_type ? nm->base_type : nm->type));
+        const struct NCDModule *nm = &group->modules[num_inited_modules];
+        const char *base_type = (nm->base_type ? nm->base_type : nm->type);
+        struct NCDModuleIndex_base_type *bt = find_base_type(o, base_type);
         if (bt) {
-            ASSERT(bt->group == group)
+            ASSERT(bt->group == ig)
             BAVL_Remove(&o->base_types_tree, &bt->base_types_tree_node);
-            free(bt);
+            BFree(bt);
         }
 #endif
-        
         if (m->method_id >= 0) {
             NCDMethodIndex_RemoveMethod(&o->method_index, m->method_id);
         }
     }
     if (group->func_globalfree) {
-        group->func_globalfree();
+        group->func_globalfree(&ig->igroup);
     }
+fail2:
+    BFree(ig->igroup.strings);
 fail1:
     LinkedList0_Remove(&o->groups_list, &ig->groups_list_node);
     BFree(ig);
@@ -330,7 +343,7 @@ fail0:
     return 0;
 }
 
-const struct NCDModule * NCDModuleIndex_FindModule (NCDModuleIndex *o, const char *type)
+const struct NCDInterpModule * NCDModuleIndex_FindModule (NCDModuleIndex *o, const char *type)
 {
     DebugObject_Access(&o->d_obj);
     ASSERT(type)
@@ -340,7 +353,7 @@ const struct NCDModule * NCDModuleIndex_FindModule (NCDModuleIndex *o, const cha
         return NULL;
     }
     
-    return m->module;
+    return &m->imodule;
 }
 
 int NCDModuleIndex_GetMethodNameId (NCDModuleIndex *o, const char *method_name)
@@ -351,7 +364,7 @@ int NCDModuleIndex_GetMethodNameId (NCDModuleIndex *o, const char *method_name)
     return NCDMethodIndex_GetMethodNameId(&o->method_index, method_name);
 }
 
-const struct NCDModule * NCDModuleIndex_GetMethodModule (NCDModuleIndex *o, NCD_string_id_t obj_type, int method_name_id)
+const struct NCDInterpModule * NCDModuleIndex_GetMethodModule (NCDModuleIndex *o, NCD_string_id_t obj_type, int method_name_id)
 {
     DebugObject_Access(&o->d_obj);
     

+ 8 - 13
ncd/NCDModuleIndex.h

@@ -38,40 +38,35 @@
 #include <ncd/NCDModule.h>
 #include <ncd/NCDMethodIndex.h>
 
-#define NCDMODULEINDEX_MAX_TYPE_LEN 39
-#define NCDMODULEINDEX_MAX_MODULES 256
 #define NCDMODULEINDEX_MODULES_HASH_SIZE 512
 
 struct NCDModuleIndex_module {
-    const struct NCDModule *module;
-    int hash_next;
+    struct NCDInterpModule imodule;
+    struct NCDModuleIndex_module *hash_next;
     int method_id;
-    char type[NCDMODULEINDEX_MAX_TYPE_LEN + 1];
 };
 
 #ifndef NDEBUG
 struct NCDModuleIndex_base_type {
     const char *base_type;
-    const struct NCDModuleGroup *group;
+    struct NCDModuleIndex_group *group;
     BAVLNode base_types_tree_node;
 };
 #endif
 
 struct NCDModuleIndex_group {
-    const struct NCDModuleGroup *group;
     LinkedList0Node groups_list_node;
+    struct NCDInterpModuleGroup igroup;
+    struct NCDModuleIndex_module modules[];
 };
 
-typedef struct NCDModuleIndex_module NCDModuleIndex__mhash_entry;
+typedef struct NCDModuleIndex_module *NCDModuleIndex__mhash_link;
 typedef const char *NCDModuleIndex__mhash_key;
-typedef struct NCDModuleIndex_module *NCDModuleIndex__mhash_arg;
 
 #include "NCDModuleIndex_mhash.h"
 #include <structure/CHash_decl.h>
 
 typedef struct {
-    struct NCDModuleIndex_module *modules;
-    int num_modules;
     NCDModuleIndex__MHash modules_hash;
 #ifndef NDEBUG
     BAVL base_types_tree;
@@ -84,8 +79,8 @@ typedef struct {
 int NCDModuleIndex_Init (NCDModuleIndex *o, NCDStringIndex *string_index) WARN_UNUSED;
 void NCDModuleIndex_Free (NCDModuleIndex *o);
 int NCDModuleIndex_AddGroup (NCDModuleIndex *o, const struct NCDModuleGroup *group, const struct NCDModuleInst_iparams *iparams, NCDStringIndex *string_index) WARN_UNUSED;
-const struct NCDModule * NCDModuleIndex_FindModule (NCDModuleIndex *o, const char *type);
+const struct NCDInterpModule * NCDModuleIndex_FindModule (NCDModuleIndex *o, const char *type);
 int NCDModuleIndex_GetMethodNameId (NCDModuleIndex *o, const char *method_name);
-const struct NCDModule * NCDModuleIndex_GetMethodModule (NCDModuleIndex *o, NCD_string_id_t obj_type, int method_name_id);
+const struct NCDInterpModule * NCDModuleIndex_GetMethodModule (NCDModuleIndex *o, NCD_string_id_t obj_type, int method_name_id);
 
 #endif

+ 8 - 8
ncd/NCDModuleIndex_mhash.h

@@ -1,12 +1,12 @@
 #define CHASH_PARAM_NAME NCDModuleIndex__MHash
-#define CHASH_PARAM_ENTRY NCDModuleIndex__mhash_entry
-#define CHASH_PARAM_LINK int
+#define CHASH_PARAM_ENTRY struct NCDModuleIndex_module
+#define CHASH_PARAM_LINK NCDModuleIndex__mhash_link
 #define CHASH_PARAM_KEY NCDModuleIndex__mhash_key
-#define CHASH_PARAM_ARG NCDModuleIndex__mhash_arg
-#define CHASH_PARAM_NULL ((int)-1)
-#define CHASH_PARAM_DEREF(arg, link) (&(arg)[(link)])
-#define CHASH_PARAM_ENTRYHASH(arg, entry) (badvpn_djb2_hash((const uint8_t *)(entry).ptr->type))
+#define CHASH_PARAM_ARG int
+#define CHASH_PARAM_NULL ((NCDModuleIndex__mhash_link)NULL)
+#define CHASH_PARAM_DEREF(arg, link) (link)
+#define CHASH_PARAM_ENTRYHASH(arg, entry) (badvpn_djb2_hash((const uint8_t *)(entry).ptr->imodule.module.type))
 #define CHASH_PARAM_KEYHASH(arg, key) (badvpn_djb2_hash((const uint8_t *)(key)))
-#define CHASH_PARAM_COMPARE_ENTRIES(arg, entry1, entry2) (!strcmp((entry1).ptr->type, (entry2).ptr->type))
-#define CHASH_PARAM_COMPARE_KEY_ENTRY(arg, key1, entry2) (!strcmp((key1), (entry2).ptr->type))
+#define CHASH_PARAM_COMPARE_ENTRIES(arg, entry1, entry2) (!strcmp((entry1).ptr->imodule.module.type, (entry2).ptr->imodule.module.type))
+#define CHASH_PARAM_COMPARE_KEY_ENTRY(arg, key1, entry2) (!strcmp((key1), (entry2).ptr->imodule.module.type))
 #define CHASH_PARAM_ENTRY_NEXT hash_next

+ 1 - 1
ncd/modules/depend.c

@@ -154,7 +154,7 @@ static void provide_promote (struct provide *o)
     }
 }
 
-static int func_globalinit (const struct NCDModuleInst_iparams *params)
+static int func_globalinit (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params)
 {
     // init provides list
     LinkedList1_Init(&provides);

+ 1 - 1
ncd/modules/dynamic_depend.c

@@ -278,7 +278,7 @@ static void name_start_resetting (struct name *o)
     name_continue_resetting(o);
 }
 
-static int func_globalinit (const struct NCDModuleInst_iparams *params)
+static int func_globalinit (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params)
 {
     // init names tree
     BAVL_Init(&names_tree, OFFSET_DIFF(struct name, name, names_tree_node), name_string_comparator, NULL);

+ 7 - 6
ncd/modules/foreach.c

@@ -80,6 +80,7 @@
 #include <generated/blog_channel_ncd_foreach.h>
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+#define ModuleString(i, id) ((i)->m->group->strings[(id)])
 
 #define ISTATE_WORKING 1
 #define ISTATE_UP 2
@@ -140,8 +141,8 @@ static void instance_free (struct instance *o);
 
 enum {STRING_INDEX, STRING_ELEM, STRING_KEY, STRING_VAL};
 
-static struct NCD_string_request strings[] = {
-    {"_index"}, {"_elem"}, {"_key"}, {"_val"}, {NULL}
+static const char *strings[] = {
+    "_index", "_elem", "_key", "_val", NULL
 };
 
 static void assert_state (struct instance *o)
@@ -588,12 +589,12 @@ static void func_new_foreach (void *vo, NCDModuleInst *i, const struct NCDModule
     
     switch (NCDVal_Type(arg_collection)) {
         case NCDVAL_LIST: {
-            name1 = strings[STRING_INDEX].id;
-            name2 = strings[STRING_ELEM].id;
+            name1 = ModuleString(i, STRING_INDEX);
+            name2 = ModuleString(i, STRING_ELEM);
         } break;
         case NCDVAL_MAP: {
-            name1 = strings[STRING_KEY].id;
-            name2 = strings[STRING_VAL].id;
+            name1 = ModuleString(i, STRING_KEY);
+            name2 = ModuleString(i, STRING_VAL);
         } break;
         default:
             ModuleLog(i, BLOG_ERROR, "invalid collection type");

+ 1 - 1
ncd/modules/multidepend.c

@@ -163,7 +163,7 @@ static void depend_update (struct depend *o)
     }
 }
 
-static int func_globalinit (const struct NCDModuleInst_iparams *params)
+static int func_globalinit (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params)
 {
     // init provides list
     LinkedList1_Init(&provides_list);

+ 1 - 1
ncd/modules/net_dns.c

@@ -181,7 +181,7 @@ fail0:
     return ret;
 }
 
-static int func_globalinit (const struct NCDModuleInst_iparams *params)
+static int func_globalinit (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params)
 {
     LinkedList1_Init(&instances);
     

+ 2 - 2
ncd/modules/net_iptables.c

@@ -379,7 +379,7 @@ static void lock_job_handler (struct lock_instance *o)
     }
 }
 
-static int func_globalinit (const struct NCDModuleInst_iparams *params)
+static int func_globalinit (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params)
 {
     // init iptables lock
     BEventLock_Init(&iptables_lock, BReactor_PendingGroup(params->reactor));
@@ -387,7 +387,7 @@ static int func_globalinit (const struct NCDModuleInst_iparams *params)
     return 1;
 }
 
-static void func_globalfree (void)
+static void func_globalfree (struct NCDInterpModuleGroup *group)
 {
     // free iptables lock
     BEventLock_Free(&iptables_lock);

+ 7 - 6
ncd/modules/parse.c

@@ -64,6 +64,7 @@
 #include <generated/blog_channel_ncd_parse.h>
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+#define ModuleString(i, id) ((i)->m->group->strings[(id)])
 
 struct instance {
     NCDModuleInst *i;
@@ -86,8 +87,8 @@ struct ipv6_cidr_instance {
 
 enum {STRING_ADDR, STRING_PREFIX};
 
-static struct NCD_string_request strings[] = {
-    {"addr"}, {"prefix"}, {NULL}
+static const char *strings[] = {
+    "addr", "prefix", NULL
 };
 
 typedef int (*parse_func) (NCDModuleInst *i, const char *str, size_t str_len, NCDValMem *mem, NCDValRef *out);
@@ -275,10 +276,10 @@ static int ipv4_cidr_addr_func_getvar2 (void *vo, NCD_string_id_t name, NCDValMe
     if (name == NCD_STRING_EMPTY) {
         ipaddr_print_ifaddr(o->ifaddr, str);
     }
-    else if (name == strings[STRING_ADDR].id) {
+    else if (name == ModuleString(o->i, STRING_ADDR)) {
         ipaddr_print_addr(o->ifaddr.addr, str);
     }
-    else if (name == strings[STRING_PREFIX].id) {
+    else if (name == ModuleString(o->i, STRING_PREFIX)) {
         sprintf(str, "%d", o->ifaddr.prefix);
     }
     else {
@@ -331,10 +332,10 @@ static int ipv6_cidr_addr_func_getvar2 (void *vo, NCD_string_id_t name, NCDValMe
     if (name == NCD_STRING_EMPTY) {
         ipaddr6_print_ifaddr(o->ifaddr, str);
     }
-    else if (name == strings[STRING_ADDR].id) {
+    else if (name == ModuleString(o->i, STRING_ADDR)) {
         ipaddr6_print_addr(o->ifaddr.addr, str);
     }
-    else if (name == strings[STRING_PREFIX].id) {
+    else if (name == ModuleString(o->i, STRING_PREFIX)) {
         sprintf(str, "%d", o->ifaddr.prefix);
     }
     else {

+ 6 - 5
ncd/modules/socket.c

@@ -151,6 +151,7 @@
 #include <generated/blog_channel_ncd_socket.h>
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+#define ModuleString(i, id) ((i)->m->group->strings[(id)])
 
 #define CONNECTION_TYPE_CONNECT 1
 #define CONNECTION_TYPE_LISTEN 2
@@ -213,8 +214,8 @@ struct listen_instance {
 
 enum {STRING_SOCKET, STRING_SYS_SOCKET, STRING_CLIENT_ADDR};
 
-static struct NCD_string_request strings[] = {
-    {"_socket"}, {"sys.socket"}, {"client_addr"}, {NULL}
+static const char *strings[] = {
+    "_socket", "sys.socket", "client_addr", NULL
 };
 
 static int parse_options (NCDModuleInst *i, NCDValRef options, size_t *out_read_size);
@@ -533,8 +534,8 @@ static int connection_process_func_getspecialobj (struct NCDModuleProcess_s *pro
     struct connection *o = UPPER_OBJECT(process, struct connection, listen.process);
     ASSERT(o->type == CONNECTION_TYPE_LISTEN)
     
-    if (name == strings[STRING_SOCKET].id) {
-        *out_object = NCDObject_Build(strings[STRING_SYS_SOCKET].id, o, connection_process_socket_obj_func_getvar, NCDObject_no_getobj);
+    if (name == ModuleString(o->listen.listen_inst->i, STRING_SOCKET)) {
+        *out_object = NCDObject_Build(ModuleString(o->listen.listen_inst->i, STRING_SYS_SOCKET), o, connection_process_socket_obj_func_getvar, NCDObject_no_getobj);
         return 1;
     }
     
@@ -546,7 +547,7 @@ static int connection_process_socket_obj_func_getvar (const NCDObject *obj, NCD_
     struct connection *o = NCDObject_DataPtr(obj);
     ASSERT(o->type == CONNECTION_TYPE_LISTEN)
     
-    if (name == strings[STRING_CLIENT_ADDR].id) {
+    if (name == ModuleString(o->listen.listen_inst->i, STRING_CLIENT_ADDR)) {
         *out_value = ncd_make_baddr(o->listen.addr, mem);
         if (NCDVal_IsInvalid(*out_value)) {
             connection_log(o, BLOG_ERROR, "ncd_make_baddr failed");

+ 6 - 5
ncd/modules/sys_evdev.c

@@ -67,6 +67,7 @@
 #include "linux_input_names.h"
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+#define ModuleString(i, id) ((i)->m->group->strings[(id)])
 
 struct instance {
     NCDModuleInst *i;
@@ -80,8 +81,8 @@ static void instance_free (struct instance *o, int is_error);
 
 enum {STRING_VALUE, STRING_CODE_NUMERIC, STRING_CODE};
 
-static struct NCD_string_request strings[] = {
-    {"value"}, {"code_numeric"}, {"code"}, {NULL}
+static const char *strings[] = {
+    "value", "code_numeric", "code", NULL
 };
 
 #define MAKE_LOOKUP_FUNC(_name_) \
@@ -239,19 +240,19 @@ static int func_getvar2 (void *vo, NCD_string_id_t name, NCDValMem *mem, NCDValR
         return 1;
     }
     
-    if (name == strings[STRING_VALUE].id) {
+    if (name == ModuleString(o->i, STRING_VALUE)) {
         char str[50];
         snprintf(str, sizeof(str), "%"PRIi32, o->event.value);
         *out = NCDVal_NewString(mem, str);
         return 1;
     }
     
-    if (name == strings[STRING_CODE_NUMERIC].id) {
+    if (name == ModuleString(o->i, STRING_CODE_NUMERIC)) {
         *out = ncd_make_uintmax(mem, o->event.code);
         return 1;
     }
     
-    if (name == strings[STRING_CODE].id) {
+    if (name == ModuleString(o->i, STRING_CODE)) {
         const char *str = "unknown";
         
         #define MAKE_CASE(_evname_, _name_) \

+ 5 - 4
ncd/modules/sys_request_client.c

@@ -96,6 +96,7 @@
 #include <generated/blog_channel_ncd_sys_request_client.h>
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+#define ModuleString(i, id) ((i)->m->group->strings[(id)])
 
 #define CSTATE_CONNECTING 1
 #define CSTATE_CONNECTED 2
@@ -164,8 +165,8 @@ static void request_instance_free (struct request_instance *o, int with_error);
 
 enum {STRING_REPLY, STRING_DATA};
 
-static struct NCD_string_request strings[] = {
-    {"_reply"}, {"data"}, {NULL}
+static const char *strings[] = {
+    "_reply", "data", NULL
 };
 
 static void client_handler_error (struct instance *o)
@@ -328,7 +329,7 @@ static int request_process_func_getspecialobj (NCDModuleProcess *process, NCD_st
         return 1;
     }
     
-    if (!o->process_is_finished && name == strings[STRING_REPLY].id) {
+    if (!o->process_is_finished && name == ModuleString(o->i, STRING_REPLY)) {
         *out_object = NCDObject_Build(-1, o, request_process_reply_obj_func_getvar, NCDObject_no_getobj);
         return 1;
     }
@@ -350,7 +351,7 @@ static int request_process_reply_obj_func_getvar (const NCDObject *obj, NCD_stri
     ASSERT(o->pstate != RPSTATE_NONE)
     ASSERT(!o->process_is_finished)
     
-    if (name == strings[STRING_DATA].id) {
+    if (name == ModuleString(o->i, STRING_DATA)) {
         *out = NCDVal_NewCopy(mem, o->process_reply_data);
         return 1;
     }

+ 8 - 7
ncd/modules/sys_request_server.c

@@ -91,6 +91,7 @@
 #include <generated/blog_channel_ncd_sys_request_server.h>
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+#define ModuleString(i, id) ((i)->m->group->strings[(id)])
 
 #define SEND_PAYLOAD_MTU 32768
 #define RECV_PAYLOAD_MTU 32768
@@ -169,9 +170,9 @@ static void instance_free (struct instance *o);
 enum {STRING_REQUEST, STRING_DATA, STRING_CLIENT_ADDR,
       STRING_SYS_REQUEST_SERVER_REQUEST};
 
-static struct NCD_string_request strings[] = {
-    {"_request"}, {"data"}, {"client_addr"},
-    {"sys.request_server.request"}, {NULL}
+static const char *strings[] = {
+    "_request", "data", "client_addr",
+    "sys.request_server.request", NULL
 };
 
 static void listener_handler (struct instance *o)
@@ -480,8 +481,8 @@ static int request_process_func_getspecialobj (NCDModuleProcess *process, NCD_st
 {
     struct request *r = UPPER_OBJECT(process, struct request, process);
     
-    if (name == strings[STRING_REQUEST].id) {
-        *out_object = NCDObject_Build(strings[STRING_SYS_REQUEST_SERVER_REQUEST].id, r, request_process_request_obj_func_getvar, NCDObject_no_getobj);
+    if (name == ModuleString(r->con->inst->i, STRING_REQUEST)) {
+        *out_object = NCDObject_Build(ModuleString(r->con->inst->i, STRING_SYS_REQUEST_SERVER_REQUEST), r, request_process_request_obj_func_getvar, NCDObject_no_getobj);
         return 1;
     }
     
@@ -492,12 +493,12 @@ static int request_process_request_obj_func_getvar (const NCDObject *obj, NCD_st
 {
     struct request *r = NCDObject_DataPtr(obj);
     
-    if (name == strings[STRING_DATA].id) {
+    if (name == ModuleString(r->con->inst->i, STRING_DATA)) {
         *out = NCDVal_NewCopy(mem, r->request_data);
         return 1;
     }
     
-    if (name == strings[STRING_CLIENT_ADDR].id) {
+    if (name == ModuleString(r->con->inst->i, STRING_CLIENT_ADDR)) {
         *out = ncd_make_baddr(r->con->addr, mem);
         return 1;
     }

+ 5 - 4
ncd/modules/try.c

@@ -67,6 +67,7 @@
 #include <generated/blog_channel_ncd_try.h>
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+#define ModuleString(i, id) ((i)->m->group->strings[(id)])
 
 struct instance {
     NCDModuleInst *i;
@@ -88,8 +89,8 @@ static void instance_free (struct instance *o);
 
 enum {STRING_TRY, STRING_TRY_TRY};
 
-static struct NCD_string_request strings[] = {
-    {"_try"}, {"try.try"}, {NULL}
+static const char *strings[] = {
+    "_try", "try.try", NULL
 };
 
 static void process_handler_event (NCDModuleProcess *process, int event)
@@ -142,8 +143,8 @@ static int process_func_getspecialobj (NCDModuleProcess *process, NCD_string_id_
         return 1;
     }
     
-    if (name == strings[STRING_TRY].id) {
-        *out_object = NCDObject_Build(strings[STRING_TRY_TRY].id, o, NCDObject_no_getvar, NCDObject_no_getobj);
+    if (name == ModuleString(o->i, STRING_TRY)) {
+        *out_object = NCDObject_Build(ModuleString(o->i, STRING_TRY_TRY), o, NCDObject_no_getvar, NCDObject_no_getobj);
         return 1;
     }
     

+ 6 - 5
ncd/modules/value.c

@@ -167,6 +167,7 @@
 #include <generated/blog_channel_ncd_value.h>
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+#define ModuleString(i, id) ((i)->m->group->strings[(id)])
 
 #define IDSTRING_TYPE (NCDVAL_STRING | (1 << 3))
 
@@ -256,8 +257,8 @@ static void valref_break (struct valref *r);
 
 enum {STRING_EXISTS, STRING_KEYS};
 
-static struct NCD_string_request strings[] = {
-    {"exists"}, {"keys"}, {NULL}
+static const char *strings[] = {
+    "exists", "keys", NULL
 };
 
 #include "value_maptree.h"
@@ -1105,13 +1106,13 @@ static int func_getvar2 (void *vo, NCD_string_id_t name, NCDValMem *mem, NCDValR
     struct instance *o = vo;
     struct value *v = valref_val(&o->ref);
     
-    if (name == strings[STRING_EXISTS].id) {
+    if (name == ModuleString(o->i, STRING_EXISTS)) {
         *out = ncd_make_boolean(mem, !!v, o->i->params->iparams->string_index);
         return 1;
     }
     
     if (name != NCD_STRING_TYPE && name != NCD_STRING_LENGTH &&
-        name != strings[STRING_KEYS].id && name != NCD_STRING_EMPTY) {
+        name != ModuleString(o->i, STRING_KEYS) && name != NCD_STRING_EMPTY) {
         return 0;
     }
     
@@ -1144,7 +1145,7 @@ static int func_getvar2 (void *vo, NCD_string_id_t name, NCDValMem *mem, NCDValR
         
         *out = ncd_make_uintmax(mem, len);
     }
-    else if (name == strings[STRING_KEYS].id) {
+    else if (name == ModuleString(o->i, STRING_KEYS)) {
         if (v->type != NCDVAL_MAP) {
             ModuleLog(o->i, BLOG_ERROR, "value is not a map (reading keys variable)");
             return 0;