Impact: splitting after ATHROW and RETURN is required for basic blocks
to be generated at every exception handler entry so that
detect_exception_handlers() can find them all.

The correctness of the CFG generation for exception handlers is based
on the assumption that control can not be transferred to exception
handler basic block entry in other way than by catching an
exception. This implies that before every exception handler there must
be one of the following: return, athrow or a branching instruction.

Signed-off-by: Tomek Grabiec <[email protected]>
---
 Makefile                           |    3 +-
 include/jit/exception.h            |   16 ++++++
 include/jit/expression.h           |    1 +
 include/vm/bytecodes.h             |    7 +++
 jit/bytecode-to-ir.c               |    1 +
 jit/cfg-analyzer.c                 |  100 +++++++++++++++++++++++++++++------
 jit/exception.c                    |   43 +++++++++++++++
 jit/trace-jit.c                    |   18 +++++-
 regression/jvm/ExceptionsTest.java |   15 ++++--
 test/jit/Makefile                  |    1 +
 vm/bytecodes.c                     |   23 ++++++--
 11 files changed, 197 insertions(+), 31 deletions(-)
 create mode 100644 include/jit/exception.h
 create mode 100644 jit/exception.c

diff --git a/Makefile b/Makefile
index 12067db..1ea48f9 100644
--- a/Makefile
+++ b/Makefile
@@ -78,7 +78,8 @@ JIT_OBJS = \
        jit/tree-printer.o      \
        jit/typeconv-bc.o       \
        jit/vtable.o            \
-       jit/fixup-site.o
+       jit/fixup-site.o        \
+       jit/exception.o
 
 VM_OBJS = \
        vm/bitset.o             \
diff --git a/include/jit/exception.h b/include/jit/exception.h
new file mode 100644
index 0000000..6ea47f0
--- /dev/null
+++ b/include/jit/exception.h
@@ -0,0 +1,16 @@
+#ifndef _JIT_EXCEPTION_H
+#define _JIT_EXCEPTION_H
+
+#include <jit/compilation-unit.h>
+#include <vm/vm.h>
+
+struct exception_table_entry *exception_find_entry(struct methodblock *,
+                                                  unsigned long);
+
+static inline bool exception_covers(struct exception_table_entry *eh,
+                                   unsigned long offset)
+{
+       return eh->start_pc <= offset && offset < eh->end_pc;
+}
+
+#endif
diff --git a/include/jit/expression.h b/include/jit/expression.h
index c131766..ff9866f 100644
--- a/include/jit/expression.h
+++ b/include/jit/expression.h
@@ -273,6 +273,7 @@ struct expression *anewarray_expr(struct object *, struct 
expression *);
 struct expression *multianewarray_expr(struct object *);
 struct expression *arraylength_expr(struct expression *);
 struct expression *instanceof_expr(struct expression *, struct object *);
+struct expression *exception_ref_expr();
 
 unsigned long nr_args(struct expression *);
 
diff --git a/include/vm/bytecodes.h b/include/vm/bytecodes.h
index 7cf3a94..6671ac2 100644
--- a/include/vm/bytecodes.h
+++ b/include/vm/bytecodes.h
@@ -8,5 +8,12 @@ bool bc_is_branch(unsigned char);
 bool bc_is_goto(unsigned char);
 bool bc_is_wide(unsigned char);
 long bc_target_off(unsigned char *);
+bool bc_is_athrow(unsigned char);
+bool bc_is_return(unsigned char);
+
+static inline bool bc_branches_to_follower(unsigned char code)
+{
+       return bc_is_branch(code) && !bc_is_goto(code);
+}
 
 #endif
diff --git a/jit/bytecode-to-ir.c b/jit/bytecode-to-ir.c
index 0c8e699..8680efa 100644
--- a/jit/bytecode-to-ir.c
+++ b/jit/bytecode-to-ir.c
@@ -10,6 +10,7 @@
 #include <jit/bytecode-converters.h>
 #include <jit/compiler.h>
 #include <jit/statement.h>
+#include <jit/expression.h>
 
 #include <vm/bytecode.h>
 #include <vm/bytecodes.h>
diff --git a/jit/cfg-analyzer.c b/jit/cfg-analyzer.c
index 9c276f3..0cfa878 100644
--- a/jit/cfg-analyzer.c
+++ b/jit/cfg-analyzer.c
@@ -13,6 +13,7 @@
 #include <vm/bytecodes.h>
 #include <vm/stream.h>
 #include <vm/vm.h>
+#include <jit/exception.h>
 
 #include <errno.h>
 #include <stdlib.h>
@@ -20,17 +21,7 @@
 
 static bool is_exception_handler(struct basic_block *bb)
 {
-       struct methodblock *method = bb->b_parent->method;
-       int i;
-
-       for (i = 0; i < method->exception_table_size; i++) {
-               struct exception_table_entry *eh = &method->exception_table[i];
-
-               if (eh->handler_pc == bb->start)
-                       return true;
-       }
-
-       return false;
+       return (exception_find_entry(bb->b_parent->method, bb->start) != NULL);
 }
 
 static void detect_exception_handlers(struct compilation_unit *cu)
@@ -81,6 +72,11 @@ static void split_at_branch_targets(struct compilation_unit 
*cu,
        }
 }
 
+static inline bool bc_ends_basic_block(unsigned char code)
+{
+       return bc_is_branch(code) || bc_is_athrow(code) || bc_is_return(code);
+}
+
 static void split_after_branches(struct stream *stream,
                                 struct basic_block *entry_bb,
                                 struct bitset *branch_targets)
@@ -97,26 +93,85 @@ static void split_after_branches(struct stream *stream,
 
                code = stream->current;
 
-               if (!bc_is_branch(*code))
+               if (!bc_ends_basic_block(*code))
                        continue;
 
                offset = stream_offset(stream);
-               br_target_off = bc_target_off(code) + offset;
                next_insn_off = offset + bc_insn_size(code);
 
                new_bb = bb_split(bb, next_insn_off);
-               if (!bc_is_goto(*code))
+               if (bc_is_branch(*code) && !bc_is_goto(*code))
                        bb_add_successor(bb, new_bb);
 
-               bb->br_target_off = br_target_off;
-               bb->has_branch = true;
+               if (bc_is_branch(*code)) {
+                       br_target_off = bc_target_off(code) + offset;
 
-               set_bit(branch_targets->bits, br_target_off);
+                       bb->br_target_off = br_target_off;
+                       bb->has_branch = true;
+
+                       set_bit(branch_targets->bits, br_target_off);
+               }
 
                bb = new_bb;
        }
 }
 
+static void update_athrow_successors(struct stream *stream,
+                                    struct compilation_unit *cu)
+{
+       struct methodblock *method;
+
+       method = cu->method;
+
+       for (; stream_has_more(stream); stream_advance(stream)) {
+               struct basic_block *bb;
+               unsigned long offset;
+               int i;
+
+               offset = stream_offset(stream);
+
+               if (!bc_is_athrow(*stream->current))
+                       continue;
+
+               bb = find_bb(cu, offset);
+
+               for (i = 0; i < method->exception_table_size; i++) {
+                       struct exception_table_entry *eh;
+
+                       eh = &method->exception_table[i];
+
+                       if (exception_covers(eh, offset)) {
+                               struct basic_block *eh_bb;
+
+                               eh_bb = find_bb(cu, eh->handler_pc);
+                               assert(eh_bb != NULL);
+
+                               bb_add_successor(bb, eh_bb);
+                       }
+               }
+       }
+}
+
+static bool all_exception_handlers_have_bb(struct compilation_unit *cu)
+{
+       struct methodblock *method = cu->method;
+       int i;
+
+       for (i = 0; i < method->exception_table_size; i++) {
+               struct exception_table_entry *eh;
+               struct basic_block *bb;
+
+               eh = &method->exception_table[i];
+               bb = find_bb(cu, eh->handler_pc);
+
+               if (bb == 0 || bb->start != eh->handler_pc)
+                       return false;
+
+       }
+
+       return true;
+}
+
 static unsigned char *bytecode_next_insn(struct stream *stream)
 {
        unsigned long opc_size;
@@ -154,7 +209,18 @@ int analyze_control_flow(struct compilation_unit *cu)
        update_branch_successors(cu);
        detect_exception_handlers(cu);
 
+       bytecode_stream_init(&stream, cu->method);
+       update_athrow_successors(&stream, cu);
+
        free(branch_targets);
 
+       /*
+        * This checks whether every exception handler has its own
+        * basic block which starts at handler_pc. There always should
+        * be a branch, athrow or return before each exception handler
+        * which will guarantee a basic block starts at exception handler.
+        */
+       assert(all_exception_handlers_have_bb(cu));
+
        return 0;
 }
diff --git a/jit/exception.c b/jit/exception.c
new file mode 100644
index 0000000..b3d3dd5
--- /dev/null
+++ b/jit/exception.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009 Tomasz Grabiec
+ *
+ * This file is released under the GPL version 2 with the following
+ * clarification and special exception:
+ *
+ *     Linking this library statically or dynamically with other modules is
+ *     making a combined work based on this library. Thus, the terms and
+ *     conditions of the GNU General Public License cover the whole
+ *     combination.
+ *
+ *     As a special exception, the copyright holders of this library give you
+ *     permission to link this library with independent modules to produce an
+ *     executable, regardless of the license terms of these independent
+ *     modules, and to copy and distribute the resulting executable under terms
+ *     of your choice, provided that you also meet, for each linked independent
+ *     module, the terms and conditions of the license of that module. An
+ *     independent module is a module which is not derived from or based on
+ *     this library. If you modify this library, you may extend this exception
+ *     to your version of the library, but you are not obligated to do so. If
+ *     you do not wish to do so, delete this exception statement from your
+ *     version.
+ *
+ * Please refer to the file LICENSE for details.
+ */
+
+#include <jit/exception.h>
+#include <jit/compilation-unit.h>
+
+struct exception_table_entry *exception_find_entry(struct methodblock *method,
+                                                  unsigned long target)
+{
+       int i;
+
+       for (i = 0; i < method->exception_table_size; i++) {
+               struct exception_table_entry *eh = &method->exception_table[i];
+
+               if (eh->handler_pc == target)
+                       return eh;
+       }
+
+       return NULL;
+}
diff --git a/jit/trace-jit.c b/jit/trace-jit.c
index f58fa20..8eaee81 100644
--- a/jit/trace-jit.c
+++ b/jit/trace-jit.c
@@ -54,12 +54,24 @@ void trace_cfg(struct compilation_unit *cu)
        struct basic_block *bb;
 
        printf("Control Flow Graph:\n\n");
-       printf("  #:\t\tRange\n");
+       printf("  #:\t\tRange\t\tSuccessors\n");
 
        for_each_basic_block(bb, &cu->bb_list) {
-               printf("  %p\t%lu..%lu", bb, bb->start, bb->end);
+               unsigned long i;
+
+               printf("  %p\t%lu..%lu\t", bb, bb->start, bb->end);
                if (bb->is_eh)
-                       printf(" (eh)\n");
+                       printf(" (eh)");
+
+               for (i = 0; i < bb->nr_successors; i++) {
+                       if (i == 0)
+                               printf("\t");
+                       else
+                               printf(", ");
+
+                       printf("%p", bb->successors[i]);
+               }
+
                printf("\n");
        }
 
diff --git a/regression/jvm/ExceptionsTest.java 
b/regression/jvm/ExceptionsTest.java
index 6ef2a08..3bd2585 100644
--- a/regression/jvm/ExceptionsTest.java
+++ b/regression/jvm/ExceptionsTest.java
@@ -11,21 +11,28 @@ package jvm;
  */
 class ExceptionsTest extends TestCase {
 
-    public static void testCatchCompilation() {
+    public static int testCatchCompilation() {
         int i;
 
         i = 0;
+
         try {
             i = 2;
         } catch (Exception e) {
-            i = 1;
+            i--;
+            return i;
+        } catch (Throwable e) {
+            i++;
         }
 
-        assertEquals(i, 2);
+    return i;
     }
 
     public static void main(String args[]) {
-        testCatchCompilation();
+        int result;
+
+        result = testCatchCompilation();
+        assertEquals(result, 2);
 
         Runtime.getRuntime().halt(retval);
     }
diff --git a/test/jit/Makefile b/test/jit/Makefile
index 8cd551e..1fb21d9 100644
--- a/test/jit/Makefile
+++ b/test/jit/Makefile
@@ -33,6 +33,7 @@ OBJS = \
        ../../jit/typeconv-bc.o \
        ../../jit/tree-printer.o \
        ../../jit/args.o \
+       ../../jit/exception.o \
        ../libharness/libharness.o \
        ../jamvm/alloc-stub.o \
        ../jamvm/resolve-stub.o \
diff --git a/vm/bytecodes.c b/vm/bytecodes.c
index 8b7666a..a8d308f 100644
--- a/vm/bytecodes.c
+++ b/vm/bytecodes.c
@@ -19,6 +19,7 @@ enum bytecode_type {
        BC_NORMAL = 0x01,
        BC_BRANCH = 0x02,
        BC_WIDE   = 0x04,
+       BC_RETURN = 0x08,
 };
 
 struct bytecode_info {
@@ -58,6 +59,16 @@ bool bc_is_goto(unsigned char opc)
        return opc == OPC_GOTO;
 }
 
+bool bc_is_athrow(unsigned char opc)
+{
+       return opc == OPC_ATHROW;
+}
+
+bool bc_is_return(unsigned char opc)
+{
+       return bytecode_infos[opc].type & BC_RETURN;
+}
+
 /**
  *     bc_target_off - Return branch opcode target offset.
  *     @code: start of branch bytecode.
@@ -249,12 +260,12 @@ static struct bytecode_info bytecode_infos[] = {
        /* OPC_TABLESWITCH and OPC_LOOKUPSWITCH are variable-length.  */
        DECLARE_BC(OPC_TABLESWITCH, 0, BC_BRANCH),
        DECLARE_BC(OPC_LOOKUPSWITCH, 0, BC_BRANCH),
-       DECLARE_BC(OPC_IRETURN, 1, BC_NORMAL),
-       DECLARE_BC(OPC_LRETURN, 1, BC_NORMAL),
-       DECLARE_BC(OPC_FRETURN, 1, BC_NORMAL),
-       DECLARE_BC(OPC_DRETURN, 1, BC_NORMAL),
-       DECLARE_BC(OPC_ARETURN, 1, BC_NORMAL),
-       DECLARE_BC(OPC_RETURN, 1, BC_NORMAL),
+       DECLARE_BC(OPC_IRETURN, 1, BC_RETURN),
+       DECLARE_BC(OPC_LRETURN, 1, BC_RETURN),
+       DECLARE_BC(OPC_FRETURN, 1, BC_RETURN),
+       DECLARE_BC(OPC_DRETURN, 1, BC_RETURN),
+       DECLARE_BC(OPC_ARETURN, 1, BC_RETURN),
+       DECLARE_BC(OPC_RETURN, 1, BC_RETURN),
        DECLARE_BC(OPC_GETSTATIC, 3, BC_NORMAL),
        DECLARE_BC(OPC_PUTSTATIC, 3, BC_NORMAL),
        DECLARE_BC(OPC_GETFIELD, 3, BC_NORMAL),
-- 
1.6.0.6


------------------------------------------------------------------------------
Crystal Reports &#45; New Free Runtime and 30 Day Trial
Check out the new simplified licensign option that enables unlimited
royalty&#45;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