Signed-off-by: Tomek Grabiec <[email protected]>
---
 Makefile                 |    3 +-
 include/jit/cu-mapping.h |   11 ++
 jit/cu-mapping.c         |  245 ++++++++++++++++++++++++++++++++++++++++++++++
 jit/trampoline.c         |    3 +
 test/jit/Makefile        |    1 +
 vm/jato.c                |    2 +
 6 files changed, 264 insertions(+), 1 deletions(-)
 create mode 100644 include/jit/cu-mapping.h
 create mode 100644 jit/cu-mapping.c

diff --git a/Makefile b/Makefile
index e43b634..f791416 100644
--- a/Makefile
+++ b/Makefile
@@ -80,7 +80,8 @@ JIT_OBJS = \
        jit/vtable.o            \
        jit/fixup-site.o        \
        jit/exception.o         \
-       jit/bc-offset-mapping.o
+       jit/bc-offset-mapping.o \
+       jit/cu-mapping.o
 
 VM_OBJS = \
        vm/bitset.o             \
diff --git a/include/jit/cu-mapping.h b/include/jit/cu-mapping.h
new file mode 100644
index 0000000..5630209
--- /dev/null
+++ b/include/jit/cu-mapping.h
@@ -0,0 +1,11 @@
+#ifndef _JIT_CU_MAPPING
+#define _JIT_CU_MAPPING
+
+struct compilation_unit;
+
+void add_cu_mapping(struct compilation_unit *cu);
+void remove_cu_mapping(struct compilation_unit *cu);
+struct compilation_unit *get_cu_from_native_addr(unsigned long addr);
+void init_cu_mapping();
+
+#endif
diff --git a/jit/cu-mapping.c b/jit/cu-mapping.c
new file mode 100644
index 0000000..343e2bb
--- /dev/null
+++ b/jit/cu-mapping.c
@@ -0,0 +1,245 @@
+#include <unistd.h>
+#include <malloc.h>
+
+#include <jit/cu-mapping.h>
+#include <jit/compilation-unit.h>
+#include <vm/buffer.h>
+#include <vm/stdlib.h>
+
+/*
+ * A radix tree is used to associate native method addresses with
+ * compilation unit. Only method entry address is stored in the tree
+ * structure, so that inserting and removing compilation unit mapping
+ * is fast. When we want to find to which compilation unit given
+ * address belongs we first check the location corresponding to that
+ * address.  If method code size is less than buffer alignment size
+ * (typically 4096 bytes) then compilation unit will be found
+ * instantly. For larger methods we might end up on some level with no
+ * mapping present for given index. When that happens we search for
+ * the predecessor of that element. Predecessor search time is
+ * proportionall with the distance of the address from method entry.
+ *
+ * Below is a schematic ilustration how pointer to compilation_unit is
+ * stored in the structure based on it's method entry address. In this
+ * example it is assumed that address is 32-bit long, buffer
+ * alignment (page size) is 2^10 and KEY_BITS is equal to 6.
+ *
+ *
+ *                                            /----------/-- buffer alignment
+ *                                            |          |
+ *  buffer_ptr --> xxxx xxxx xxxx xxxx xxxx xx00 0000 0000
+ *                  \                         \
+ *                   \                         \
+ *                    \                         \
+ *                     \                         \
+ *                      \                         \
+ *                       \                         \
+ *  key -->   0000 0000 00xx xxxx xxxx xxxx xxxx xxxx
+ *                      |     ||     | |     ||     |
+ *                      \-----/\-----/ \-----/\-----/
+ *                       |       |         |    |
+ *                      /       /          |    |
+ *                     /       /           |     \
+ *                    /       /            |      \
+ *                   /        |            |       \
+ *                  /         |            |        \
+ *                 |          |            |         \
+ *       +----+-+-+-+-+..+-+  |            |          \
+ * root: |NULL| | | | |  | |  |            |           \
+ *       +----+-+-+-+-+..+-+  |            |            |
+ *       level 0   |          |            |            |
+ *                 |  +----+-+-+-+-+..+-+  |            |
+ *                  > |    | | | | |  | |  |            |
+ *                    +----+-+-+-+-+..+-+  |            |
+ *                    level 1 |            |            |
+ *                            |    +----+-+-+-+-+..+-+  |
+ *                             ->  |    | | | | |  | |  |
+ *                                 +----+-+-+-+-+..+-+  |
+ *                                 level 2 |            |
+ *                                         |    +----+-+-+-+-+..+-+
+ *                                          ->  |    | | | | |  | |
+ *                                              +----+-+-+-+-+..+-+
+ *                                              level 3 |
+ *                                                      v
+ *                                             +------------------+
+ *                                             | compilation_unit |
+ *                                             +------------------+
+ *
+ */
+
+#define KEY_BITS 6
+#define SLOT_COUNT (1 << KEY_BITS)
+
+const unsigned long key_mask = ((1ul << KEY_BITS) - 1);
+int level_count;
+
+struct radix_tree_node {
+       struct radix_tree_node *parent;
+       int count; /* number of nonempty slots */
+       void *slots[SLOT_COUNT];
+};
+
+int buffer_alignment_bits;
+
+struct radix_tree_node * root = NULL;
+
+static struct radix_tree_node *
+alloc_radix_tree_node(struct radix_tree_node *parent)
+{
+       struct radix_tree_node *node;
+
+       node = zalloc(sizeof(struct radix_tree_node));
+       if (!node)
+               return NULL;
+
+       node->parent = parent;
+
+       return node;
+}
+
+void init_cu_mapping()
+{
+       int page_size = getpagesize();
+       int viable_key_bits;
+
+       while (page_size > 0) {
+               buffer_alignment_bits++;
+               page_size >>= 1;
+       }
+
+       viable_key_bits = sizeof(unsigned long) * 8 - buffer_alignment_bits;
+       level_count = (viable_key_bits + KEY_BITS - 1) / KEY_BITS;
+
+       root = alloc_radix_tree_node(NULL);
+}
+
+static void *tree_last(struct radix_tree_node *node, int level)
+{
+       int i;
+
+       while (level < level_count) {
+               for (i = SLOT_COUNT - 1; i >= 0; i--)
+                       if (node->slots[i] != NULL) {
+                               node = node->slots[i];
+                               level++;
+                               break;
+                       }
+
+               if (i < 0)
+                       return NULL;
+       }
+
+       return node;
+}
+
+static unsigned long get_index(unsigned long key, int level)
+{
+       int shift = ((level_count - level - 1) * KEY_BITS);
+
+       return (key >> shift) & key_mask;
+}
+
+static void *tree_previous(struct radix_tree_node *node, unsigned long key,
+                          int level)
+{
+       unsigned long index;
+
+       /* we don't have to search this level if there are no
+          other slots */
+       while (node != NULL && node->count == 1) {
+               node = node->parent;
+               level--;
+       }
+
+       if (node == NULL)
+               return NULL;
+
+       for (index = get_index(key, level); index >= 0; index--)
+               if (node->slots[index] != NULL)
+                       return tree_last(node->slots[index], level + 1);
+
+       return tree_previous(node->parent, key, level - 1);
+}
+
+void add_cu_mapping(struct compilation_unit *cu)
+{
+       struct radix_tree_node *node = root;
+       unsigned long key;
+       int i;
+
+       key = (unsigned long)buffer_ptr(cu->objcode) >> buffer_alignment_bits;
+
+       for (i = 0; i<level_count-1; i++) {
+               int index = get_index(key, i);
+
+               if (node->slots[index] == NULL)
+                       node->slots[index] = alloc_radix_tree_node(node);
+
+               node = node->slots[index];
+       }
+
+       node->count++;
+       node->slots[get_index(key, i)] = cu;
+}
+
+static void free_slot(struct radix_tree_node *node, int key, int level)
+{
+       node->slots[get_index(key, level)] = NULL;
+       node->count--;
+
+       if (node->count == 0 && node->parent != NULL) {
+               free(node);
+               free_slot(node->parent, key, level - 1);
+       }
+}
+
+void remove_cu_mapping(struct compilation_unit *cu)
+{
+       int i;
+       struct radix_tree_node *node = root;
+       unsigned long key;
+
+       key = (unsigned long)buffer_ptr(cu->objcode) >> buffer_alignment_bits;
+
+       for (i = 0; i < level_count - 1; i++) {
+               int index = get_index(key, i);
+
+               if (node->slots[index] == NULL)
+                       return; /* no mapping exists */
+
+               node = node->slots[index];
+       }
+
+       free_slot(node, key, i);
+}
+
+static struct compilation_unit *find_cu(unsigned long addr)
+{
+       int i;
+       struct radix_tree_node *node = root;
+       unsigned long key;
+
+       key = addr >> buffer_alignment_bits;
+
+       for (i = 0; i < level_count; i++) {
+               int index = get_index(key, i);
+
+               if (node->slots[index] == NULL)
+                       return tree_previous(node, key, i);
+
+               node = node->slots[index];
+       }
+
+       return (struct compilation_unit *)node;
+}
+
+struct compilation_unit *get_cu_from_native_addr(unsigned long addr)
+{
+       struct compilation_unit *cu = find_cu(addr);
+       unsigned long method_addr = (unsigned long)buffer_ptr(cu->objcode);
+
+       if (method_addr + buffer_offset(cu->objcode) <= addr)
+               return NULL;
+
+       return cu;
+}
diff --git a/jit/trampoline.c b/jit/trampoline.c
index cab6c09..a123d7a 100644
--- a/jit/trampoline.c
+++ b/jit/trampoline.c
@@ -25,6 +25,7 @@
  */
 
 #include <jit/compiler.h>
+#include <jit/cu-mapping.h>
 #include <vm/buffer.h>
 #include <vm/natives.h>
 #include <vm/vm.h>
@@ -52,6 +53,8 @@ static void *jit_java_trampoline(struct compilation_unit *cu)
        if (!cu->is_compiled)
                compile(cu);
 
+       add_cu_mapping(cu);
+
        return buffer_ptr(cu->objcode);
 }
 
diff --git a/test/jit/Makefile b/test/jit/Makefile
index 89d1489..3ec6fd4 100644
--- a/test/jit/Makefile
+++ b/test/jit/Makefile
@@ -35,6 +35,7 @@ OBJS = \
        ../../jit/args.o \
        ../../jit/exception.o \
        ../../jit/bc-offset-mapping.o \
+       ../../jit/cu-mapping.o \
        ../libharness/libharness.o \
        ../jamvm/alloc-stub.o \
        ../jamvm/resolve-stub.o \
diff --git a/vm/jato.c b/vm/jato.c
index 9ac1e99..b3c27bd 100644
--- a/vm/jato.c
+++ b/vm/jato.c
@@ -29,6 +29,7 @@
 #include <vm/signal.h>
 #include <vm/vm.h>
 #include <jit/compiler.h>
+#include <jit/cu-mapping.h>
 
 #ifdef USE_ZIP
 #define BCP_MESSAGE "<jar/zip files and directories separated by :>"
@@ -297,6 +298,7 @@ int main(int argc, char *argv[]) {
     exe_name = argv[0];
 
     setup_signal_handlers();
+    init_cu_mapping();
 
     setDefaultInitArgs(&args);
     int class_arg = parseCommandLine(argc, argv, &args);
-- 
1.6.0.6


------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables 
unlimited royalty-free distribution of the report engine 
for externally facing server and web deployment. 
http://p.sf.net/sfu/businessobjects
_______________________________________________
Jatovm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to