Przeglądaj źródła

ncd: add NCDInterpBlock and NCDInterpProg, to be used for speeding up certain operations during interpretation

ambrop7 13 lat temu
rodzic
commit
a75e507a34

+ 2 - 0
ncd/CMakeLists.txt

@@ -68,6 +68,8 @@ add_executable(badvpn-ncd
     NCDIfConfig.c
     NCDObject.c
     NCDSugar.c
+    NCDInterpBlock.c
+    NCDInterpProg.c
     BEventLock.c
     modules/command_template.c
     modules/event_template.c

+ 129 - 0
ncd/NCDInterpBlock.c

@@ -0,0 +1,129 @@
+/**
+ * @file NCDInterpBlock.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include <string.h>
+
+#include <misc/balloc.h>
+#include <base/BLog.h>
+
+#include "NCDInterpBlock.h"
+
+#include <generated/blog_channel_ncd.h>
+
+static size_t djb2_hash (const unsigned char *str)
+{
+    size_t hash = 5381;
+    int c;
+
+    while (c = *str++) {
+        hash = ((hash << 5) + hash) + c;
+    }
+    
+    return hash;
+}
+
+#include "NCDInterpBlock_hash.h"
+#include <structure/CHash_impl.h>
+
+int NCDInterpBlock_Init (NCDInterpBlock *o, NCDBlock *block)
+{
+    if (NCDBlock_NumStatements(block) > INT_MAX) {
+        BLog(BLOG_ERROR, "too many statements");
+        goto fail0;
+    }
+    int num_stmts = NCDBlock_NumStatements(block);
+    
+    if (!(o->stmts = BAllocArray(num_stmts, sizeof(o->stmts[0])))) {
+        BLog(BLOG_ERROR, "BAllocArray failed");
+        goto fail0;
+    }
+    
+    if (!NCDInterpBlock__Hash_Init(&o->hash, num_stmts)) {
+        BLog(BLOG_ERROR, "NCDInterpBlock__Hash_Init failed");
+        goto fail1;
+    }
+    
+    o->num_stmts = 0;
+    
+    for (NCDStatement *s = NCDBlock_FirstStatement(block); s; s = NCDBlock_NextStatement(block, s)) {
+        struct NCDInterpBlock__stmt *e = &o->stmts[o->num_stmts];
+        
+        e->name = NCDStatement_Name(s);
+        
+        if (e->name) {
+            NCDInterpBlock__HashRef ref = NCDInterpBlock__Hash_Deref(o->stmts, o->num_stmts);
+            NCDInterpBlock__Hash_InsertMulti(&o->hash, o->stmts, ref);
+        }
+        
+        o->num_stmts++;
+    }
+    
+    ASSERT(o->num_stmts == num_stmts)
+    
+    DebugObject_Init(&o->d_obj);
+    return 1;
+    
+fail1:
+    BFree(o->stmts);
+fail0:
+    return 0;
+}
+
+void NCDInterpBlock_Free (NCDInterpBlock *o)
+{
+    DebugObject_Free(&o->d_obj);
+    
+    NCDInterpBlock__Hash_Free(&o->hash);
+    
+    BFree(o->stmts);
+}
+
+int NCDInterpBlock_FindStatement (NCDInterpBlock *o, int from_index, const char *name)
+{
+    DebugObject_Access(&o->d_obj);
+    ASSERT(from_index >= 0)
+    ASSERT(from_index <= o->num_stmts)
+    ASSERT(name)
+    
+    // We rely on that we get matching statements here in reverse order of insertion,
+    // to properly return the greatest matching statement lesser than from_index.
+    
+    NCDInterpBlock__HashRef ref = NCDInterpBlock__Hash_Lookup(&o->hash, o->stmts, name);
+    while (ref.link != NCDInterpBlock__HashNullLink()) {
+        ASSERT(!strcmp(ref.ptr->name, name))
+        if (ref.link < from_index) {
+            return ref.link;
+        }
+        ref = NCDInterpBlock__Hash_GetNextEqual(&o->hash, o->stmts, ref);
+    }
+    
+    return -1;
+}

+ 61 - 0
ncd/NCDInterpBlock.h

@@ -0,0 +1,61 @@
+/**
+ * @file NCDInterpBlock.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BADVPN_NCDINTERPBLOCK_H
+#define BADVPN_NCDINTERPBLOCK_H
+
+#include <misc/debug.h>
+#include <base/DebugObject.h>
+#include <structure/CHash.h>
+#include <ncd/NCDAst.h>
+
+struct NCDInterpBlock__stmt {
+    const char *name;
+    int hash_next;
+};
+
+typedef struct NCDInterpBlock__stmt NCDInterpBlock__hashentry;
+typedef const char *NCDInterpBlock__hashkey;
+typedef struct NCDInterpBlock__stmt *NCDInterpBlock__hasharg;
+
+#include "NCDInterpBlock_hash.h"
+#include <structure/CHash_decl.h>
+
+typedef struct {
+    struct NCDInterpBlock__stmt *stmts;
+    int num_stmts;
+    NCDInterpBlock__Hash hash;
+    DebugObject d_obj;
+} NCDInterpBlock;
+
+int NCDInterpBlock_Init (NCDInterpBlock *o, NCDBlock *block) WARN_UNUSED;
+void NCDInterpBlock_Free (NCDInterpBlock *o);
+int NCDInterpBlock_FindStatement (NCDInterpBlock *o, int from_index, const char *name);
+
+#endif

+ 11 - 0
ncd/NCDInterpBlock_hash.h

@@ -0,0 +1,11 @@
+#define CHASH_PARAM_NAME NCDInterpBlock__Hash
+#define CHASH_PARAM_ENTRY NCDInterpBlock__hashentry
+#define CHASH_PARAM_LINK int
+#define CHASH_PARAM_KEY NCDInterpBlock__hashkey
+#define CHASH_PARAM_ARG NCDInterpBlock__hasharg
+#define CHASH_PARAM_NULL ((int)-1)
+#define CHASH_PARAM_DEREF(arg, link) (&(arg)[(link)])
+#define CHASH_PARAM_HASHFUN(arg, key) (djb2_hash((const unsigned char *)(key)))
+#define CHASH_PARAM_KEYSEQUAL(arg, key1, key2) (!strcmp((key1), (key2)))
+#define CHASH_PARAM_ENTRY_KEY name
+#define CHASH_PARAM_ENTRY_NEXT hash_next

+ 143 - 0
ncd/NCDInterpProg.c

@@ -0,0 +1,143 @@
+/**
+ * @file NCDInterpProg.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include <string.h>
+
+#include <misc/balloc.h>
+#include <base/BLog.h>
+
+#include "NCDInterpProg.h"
+
+#include <generated/blog_channel_ncd.h>
+
+static size_t djb2_hash (const unsigned char *str)
+{
+    size_t hash = 5381;
+    int c;
+
+    while (c = *str++) {
+        hash = ((hash << 5) + hash) + c;
+    }
+    
+    return hash;
+}
+
+#include "NCDInterpProg_hash.h"
+#include <structure/CHash_impl.h>
+
+int NCDInterpProg_Init (NCDInterpProg *o, NCDProgram *prog)
+{
+    if (NCDProgram_NumProcesses(prog) > INT_MAX) {
+        BLog(BLOG_ERROR, "too many processes");
+        goto fail0;
+    }
+    int num_procs = NCDProgram_NumProcesses(prog);
+    
+    if (!(o->procs = BAllocArray(num_procs, sizeof(o->procs[0])))) {
+        BLog(BLOG_ERROR, "BAllocArray failed");
+        goto fail0;
+    }
+    
+    if (!NCDInterpProg__Hash_Init(&o->hash, num_procs)) {
+        BLog(BLOG_ERROR, "NCDInterpProg__Hash_Init failed");
+        goto fail1;
+    }
+    
+    o->num_procs = 0;
+    
+    for (NCDProcess *p = NCDProgram_FirstProcess(prog); p; p = NCDProgram_NextProcess(prog, p)) {
+        struct NCDInterpProg__process *e = &o->procs[o->num_procs];
+        
+        e->name = NCDProcess_Name(p);
+        e->proc = p;
+        
+        if (!NCDInterpBlock_Init(&e->iblock, NCDProcess_Block(p))) {
+            BLog(BLOG_ERROR, "NCDInterpBlock_Init failed");
+            goto fail2;
+        }
+        
+        NCDInterpProg__HashRef ref = NCDInterpProg__Hash_Deref(o->procs, o->num_procs);
+        if (!NCDInterpProg__Hash_Insert(&o->hash, o->procs, ref, NULL)) {
+            BLog(BLOG_ERROR, "duplicate process or template name: %s", e->name);
+            NCDInterpBlock_Free(&e->iblock);
+            goto fail2;
+        }
+        
+        o->num_procs++;
+    }
+    
+    ASSERT(o->num_procs == num_procs)
+    
+    DebugObject_Init(&o->d_obj);
+    return 1;
+    
+fail2:
+    while (o->num_procs-- > 0) {
+        NCDInterpBlock_Free(&o->procs[o->num_procs].iblock);
+    }
+    NCDInterpProg__Hash_Free(&o->hash);
+fail1:
+    BFree(o->procs);
+fail0:
+    return 0;
+}
+
+void NCDInterpProg_Free (NCDInterpProg *o)
+{
+    DebugObject_Free(&o->d_obj);
+    
+    while (o->num_procs-- > 0) {
+        NCDInterpBlock_Free(&o->procs[o->num_procs].iblock);
+    }
+    
+    NCDInterpProg__Hash_Free(&o->hash);
+    
+    BFree(o->procs);
+}
+
+int NCDInterpProg_FindProcess (NCDInterpProg *o, const char *name, NCDProcess **out_proc, NCDInterpBlock **out_iblock)
+{
+    DebugObject_Access(&o->d_obj);
+    ASSERT(name)
+    ASSERT(out_proc)
+    ASSERT(out_iblock)
+    
+    NCDInterpProg__HashRef ref = NCDInterpProg__Hash_Lookup(&o->hash, o->procs, name);
+    if (ref.link == NCDInterpProg__HashNullLink()) {
+        return -1;
+    }
+    
+    ASSERT(!strcmp(ref.ptr->name, name))
+    
+    *out_proc = ref.ptr->proc;
+    *out_iblock = &ref.ptr->iblock;
+    return 1;
+}

+ 64 - 0
ncd/NCDInterpProg.h

@@ -0,0 +1,64 @@
+/**
+ * @file NCDInterpProg.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BADVPN_NCDINTERPPROG_H
+#define BADVPN_NCDINTERPPROG_H
+
+#include <misc/debug.h>
+#include <base/DebugObject.h>
+#include <ncd/NCDAst.h>
+#include <ncd/NCDInterpBlock.h>
+#include <structure/CHash.h>
+
+struct NCDInterpProg__process {
+    const char *name;
+    NCDProcess *proc;
+    NCDInterpBlock iblock;
+    int hash_next;
+};
+
+typedef struct NCDInterpProg__process NCDInterpProg__hashentry;
+typedef const char *NCDInterpProg__hashkey;
+typedef struct NCDInterpProg__process *NCDInterpProg__hasharg;
+
+#include "NCDInterpProg_hash.h"
+#include <structure/CHash_decl.h>
+
+typedef struct {
+    struct NCDInterpProg__process *procs;
+    int num_procs;
+    NCDInterpProg__Hash hash;
+    DebugObject d_obj;
+} NCDInterpProg;
+
+int NCDInterpProg_Init (NCDInterpProg *o, NCDProgram *prog) WARN_UNUSED;
+void NCDInterpProg_Free (NCDInterpProg *o);
+int NCDInterpProg_FindProcess (NCDInterpProg *o, const char *name, NCDProcess **out_proc, NCDInterpBlock **out_iblock);
+
+#endif

+ 11 - 0
ncd/NCDInterpProg_hash.h

@@ -0,0 +1,11 @@
+#define CHASH_PARAM_NAME NCDInterpProg__Hash
+#define CHASH_PARAM_ENTRY NCDInterpProg__hashentry
+#define CHASH_PARAM_LINK int
+#define CHASH_PARAM_KEY NCDInterpProg__hashkey
+#define CHASH_PARAM_ARG NCDInterpProg__hasharg
+#define CHASH_PARAM_NULL ((int)-1)
+#define CHASH_PARAM_DEREF(arg, link) (&(arg)[(link)])
+#define CHASH_PARAM_HASHFUN(arg, key) (djb2_hash((const unsigned char *)(key)))
+#define CHASH_PARAM_KEYSEQUAL(arg, key1, key2) (!strcmp((key1), (key2)))
+#define CHASH_PARAM_ENTRY_KEY name
+#define CHASH_PARAM_ENTRY_NEXT hash_next