This significantly reduces the code required for doing null checks in
jitted code. In some places (eg. invokevirtual) there is no need to
insert any extra code for null checks to work because the reference to
be checked is being dereferenced by native code and will trigger
SIGSEGV when it is null. In other places null check can be reduced to
a single instruction like: test (%eax),%eax

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 arch/x86/Makefile_32                |    1 +
 arch/x86/exception_32.c             |   36 ++++++++++++++++++++++++++++++-
 arch/x86/include/arch/exception.h   |    1 +
 arch/x86/include/arch/signal.h      |    8 +++++++
 arch/x86/include/arch/stack-frame.h |    1 +
 arch/x86/signal.c                   |   39 ++++++++++++++++++++++++++++++++++
 arch/x86/use-def.c                  |    1 +
 include/jit/compilation-unit.h      |    3 +-
 include/jit/exception.h             |    3 +-
 include/vm/class.h                  |    1 +
 jit/fixup-site.c                    |    1 +
 jit/liveness.c                      |    1 +
 jit/spill-reload.c                  |    1 +
 regression/jvm/ExceptionsTest.java  |   14 ++++++++++++
 test/arch-mmix/use-def.c            |    1 +
 test/arch-x86/Makefile              |    2 +-
 test/jamvm/class-stub.c             |   40 +++++++++++++++++++++++++++++++++++
 test/jit/compilation-unit-test.c    |    1 +
 test/jit/linear-scan-test.c         |    1 +
 test/jit/spill-reload-test.c        |    1 +
 vm/class.c                          |   14 ++++++++++++
 vm/signal.c                         |   23 +++++++++++++++++--
 22 files changed, 187 insertions(+), 7 deletions(-)
 create mode 100644 arch/x86/include/arch/signal.h
 create mode 100644 arch/x86/signal.c
 create mode 100644 test/jamvm/class-stub.c

diff --git a/arch/x86/Makefile_32 b/arch/x86/Makefile_32
index 81bb5ad..784e5f7 100644
--- a/arch/x86/Makefile_32
+++ b/arch/x86/Makefile_32
@@ -9,6 +9,7 @@ ARCH_OBJS = \
        arch/x86/use-def.o              \
        arch/x86/exception_32.o         \
        arch/x86/unwind_32.o            \
+       arch/x86/signal.o               \
        jamvm/os/$(OS)/i386/dll_md.o    \
        jamvm/os/$(OS)/i386/init.o      \
        jamvm/os/$(OS)/os.o
diff --git a/arch/x86/exception_32.c b/arch/x86/exception_32.c
index 22e8028..a55adaa 100644
--- a/arch/x86/exception_32.c
+++ b/arch/x86/exception_32.c
@@ -23,10 +23,17 @@
  *
  * Please refer to the file LICENSE for details.
  */
-
+#include <signal.h>
 #include <jit/exception.h>
+#include <jit/cu-mapping.h>
+#include <jit/basic-block.h>
+#include <jit/compilation-unit.h>
 #include <arch/exception.h>
 #include <arch/stack-frame.h>
+#include <arch/memory.h>
+
+#define __USE_GNU
+#include <ucontext.h>
 
 unsigned char *throw_exception(struct compilation_unit *cu,
                               struct object *exception)
@@ -36,3 +43,30 @@ unsigned char *throw_exception(struct compilation_unit *cu,
 
        return throw_exception_from(cu, frame, native_ptr, exception);
 }
+
+void throw_exception_from_signal(void *ctx, struct object *exception)
+{
+       ucontext_t *_ctx = (ucontext_t*)ctx;
+       struct jit_stack_frame *frame;
+       struct compilation_unit *cu;
+       unsigned long source_addr;
+       void *eh;
+
+       source_addr = _ctx->uc_mcontext.gregs[REG_EIP];
+       cu = get_cu_from_native_addr(source_addr);
+       frame = (struct jit_stack_frame*)_ctx->uc_mcontext.gregs[REG_EBP];
+
+       eh = throw_exception_from(cu, frame, (unsigned char*)source_addr,
+                                 exception);
+
+       if (eh == NULL) {
+               _ctx->uc_mcontext.gregs[REG_EIP] = 
(int)bb_native_ptr(cu->exit_bb);
+       } else {
+               _ctx->uc_mcontext.gregs[REG_EIP] = (int)eh;
+
+               /* push exception object reference on stack */
+               _ctx->uc_mcontext.gregs[REG_ESP] -= sizeof(exception);
+               cpu_write_u32((unsigned char*)_ctx->uc_mcontext.gregs[REG_ESP],
+                             (uint32_t)exception);
+       }
+}
diff --git a/arch/x86/include/arch/exception.h 
b/arch/x86/include/arch/exception.h
index 1b52e6e..d816e60 100644
--- a/arch/x86/include/arch/exception.h
+++ b/arch/x86/include/arch/exception.h
@@ -8,6 +8,7 @@ struct compilation_unit;
 /* This should be called only by JIT compiled native code */
 unsigned char *throw_exception(struct compilation_unit *cu,
                               struct object *exception);
+void throw_exception_from_signal(void *ctx, struct object *exception);
 extern void unwind();
 
 #endif
diff --git a/arch/x86/include/arch/signal.h b/arch/x86/include/arch/signal.h
new file mode 100644
index 0000000..73e95cc
--- /dev/null
+++ b/arch/x86/include/arch/signal.h
@@ -0,0 +1,8 @@
+#ifndef _ARCH_SIGNAL_H
+#define _ARCH_SIGNAL_H
+
+#include <stdbool.h>
+
+bool signal_from_jit_method(void *ctx);
+
+#endif
diff --git a/arch/x86/include/arch/stack-frame.h 
b/arch/x86/include/arch/stack-frame.h
index 1bb9e0f..3d24fd8 100644
--- a/arch/x86/include/arch/stack-frame.h
+++ b/arch/x86/include/arch/stack-frame.h
@@ -2,6 +2,7 @@
 #define __X86_FRAME_H
 
 #include <jit/stack-slot.h>
+#include <stdbool.h>
 
 struct methodblock;
 struct expression;
diff --git a/arch/x86/signal.c b/arch/x86/signal.c
new file mode 100644
index 0000000..5bad631
--- /dev/null
+++ b/arch/x86/signal.c
@@ -0,0 +1,39 @@
+/*
+ * 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 <signal.h>
+#include <arch/signal.h>
+#include <arch/stack-frame.h>
+
+#define __USE_GNU
+#include <ucontext.h>
+
+bool signal_from_jit_method(void *ctx)
+{
+       ucontext_t *_ctx = (ucontext_t*)ctx;
+
+       return is_jit_method(_ctx->uc_mcontext.gregs[REG_EIP]);
+}
diff --git a/arch/x86/use-def.c b/arch/x86/use-def.c
index 8463128..ef47f59 100644
--- a/arch/x86/use-def.c
+++ b/arch/x86/use-def.c
@@ -6,6 +6,7 @@
  */
 
 #include <jit/compilation-unit.h>
+#include <arch/instruction.h>
 
 enum {
        DEF_DST         = 1,
diff --git a/include/jit/compilation-unit.h b/include/jit/compilation-unit.h
index 88d87b1..4b1891c 100644
--- a/include/jit/compilation-unit.h
+++ b/include/jit/compilation-unit.h
@@ -7,12 +7,13 @@
 #include <vm/stack.h>
 
 #include <arch/stack-frame.h>
-#include <arch/instruction.h>
 
 #include <stdbool.h>
 #include <pthread.h>
 
 struct buffer;
+struct insn;
+enum machine_reg;
 
 struct compilation_unit {
        struct methodblock *method;
diff --git a/include/jit/exception.h b/include/jit/exception.h
index 10e88fd..96483c1 100644
--- a/include/jit/exception.h
+++ b/include/jit/exception.h
@@ -1,11 +1,12 @@
 #ifndef _JIT_EXCEPTION_H
 #define _JIT_EXCEPTION_H
 
-#include <jit/compilation-unit.h>
 #include <vm/vm.h>
 #include <arch/stack-frame.h>
+#include <stdbool.h>
 
 struct jit_stack_frame;
+struct compilation_unit;
 
 struct exception_table_entry *exception_find_entry(struct methodblock *,
                                                   unsigned long);
diff --git a/include/vm/class.h b/include/vm/class.h
index 4ca0274..063498c 100644
--- a/include/vm/class.h
+++ b/include/vm/class.h
@@ -3,6 +3,7 @@
 
 #include <vm/vm.h>
 
+struct object *create_null_pointer_exception();
 unsigned long is_object_instance_of(struct object *obj, struct object *type);
 void check_null(struct object *obj);
 void check_array(struct object *obj, unsigned int index);
diff --git a/jit/fixup-site.c b/jit/fixup-site.c
index 9a63f28..51b3edb 100644
--- a/jit/fixup-site.c
+++ b/jit/fixup-site.c
@@ -25,6 +25,7 @@
  */
 
 #include <jit/compiler.h>
+#include <arch/instruction.h>
 #include <memory.h>
 #include <malloc.h>
 
diff --git a/jit/liveness.c b/jit/liveness.c
index 74b656a..820d79d 100644
--- a/jit/liveness.c
+++ b/jit/liveness.c
@@ -9,6 +9,7 @@
 #include <jit/compilation-unit.h>
 #include <jit/vars.h>
 #include <vm/bitset.h>
+#include <arch/instruction.h>
 
 #include <errno.h>
 #include <stdlib.h>
diff --git a/jit/spill-reload.c b/jit/spill-reload.c
index f8d3230..ff74c33 100644
--- a/jit/spill-reload.c
+++ b/jit/spill-reload.c
@@ -26,6 +26,7 @@
 
 #include <jit/compilation-unit.h>
 #include <jit/stack-slot.h>
+#include <arch/instruction.h>
 #include <errno.h>
 
 static struct insn *last_insn(struct live_interval *interval)
diff --git a/regression/jvm/ExceptionsTest.java 
b/regression/jvm/ExceptionsTest.java
index cf893ff..e474450 100644
--- a/regression/jvm/ExceptionsTest.java
+++ b/regression/jvm/ExceptionsTest.java
@@ -121,6 +121,19 @@ public class ExceptionsTest extends TestCase {
         } catch (Exception e) {}
     }
 
+    public static void testThrowFromSignalHandler() {
+        boolean catched = false;
+
+        try {
+            Object o = null;
+            o.getClass();
+        } catch (NullPointerException e) {
+            catched = true;
+        }
+
+        assertTrue(catched);
+    }
+
     public static void main(String args[]) {
         testTryBlockDoesNotThrowAnything();
         testThrowAndCatchInTheSameMethod();
@@ -128,6 +141,7 @@ public class ExceptionsTest extends TestCase {
         testMultipleCatchBlocks();
         testNestedTryCatch();
         testEmptyCatchBlock();
+        testThrowFromSignalHandler();
 
         exit();
     }
diff --git a/test/arch-mmix/use-def.c b/test/arch-mmix/use-def.c
index adfb599..d8a704d 100644
--- a/test/arch-mmix/use-def.c
+++ b/test/arch-mmix/use-def.c
@@ -6,6 +6,7 @@
  */
 
 #include <jit/compilation-unit.h>
+#include <arch/instruction.h>
 
 enum {
        NO_USE_DEF      = 0,
diff --git a/test/arch-x86/Makefile b/test/arch-x86/Makefile
index 0d3cea1..e2f6427 100644
--- a/test/arch-x86/Makefile
+++ b/test/arch-x86/Makefile
@@ -26,6 +26,7 @@ OBJS = \
        ../jamvm/lock.o \
        ../jamvm/thread-stub.o \
        ../jamvm/resolve-stub.o \
+       ../jamvm/class-stub.o \
        ../../arch/x86/backtrace.o \
        ../../vm/buffer.o \
        ../../vm/die.o \
@@ -34,7 +35,6 @@ OBJS = \
        ../../vm/string.o \
        ../../vm/types.o \
        ../../vm/zalloc.o \
-       ../../vm/class.o \
        ../../vm/radix-tree.o \
        ../../jit/alloc.o \
        ../../jit/basic-block.o \
diff --git a/test/jamvm/class-stub.c b/test/jamvm/class-stub.c
new file mode 100644
index 0000000..d025a34
--- /dev/null
+++ b/test/jamvm/class-stub.c
@@ -0,0 +1,40 @@
+#include <vm/vm.h>
+
+struct object *create_null_pointer_exception()
+{
+       return NULL;
+}
+
+unsigned long is_object_instance_of(struct object *obj, struct object *type)
+{
+       if (!obj)
+               return 0;
+
+       return isInstanceOf(type, obj->class);
+}
+
+void check_null(struct object *obj)
+{
+       if (!obj)
+               abort();
+}
+
+void check_array(struct object *obj, unsigned int index)
+{
+       struct classblock *cb = CLASS_CB(obj->class);
+
+       if (!IS_ARRAY(cb))
+               abort();
+
+       if (index >= ARRAY_LEN(obj))
+               abort();
+}
+
+void check_cast(struct object *obj, struct object *type)
+{
+       if (!obj)
+               return;
+
+       if (!isInstanceOf(type, obj->class))
+               abort();
+}
diff --git a/test/jit/compilation-unit-test.c b/test/jit/compilation-unit-test.c
index 7b45429..455a0d5 100644
--- a/test/jit/compilation-unit-test.c
+++ b/test/jit/compilation-unit-test.c
@@ -4,6 +4,7 @@
 
 #include <libharness.h>
 #include <jit/compilation-unit.h>
+#include <arch/instruction.h>
 #include <vm/vm.h>
 
 static struct methodblock method = { };
diff --git a/test/jit/linear-scan-test.c b/test/jit/linear-scan-test.c
index 31f1dab..e69d0c8 100644
--- a/test/jit/linear-scan-test.c
+++ b/test/jit/linear-scan-test.c
@@ -3,6 +3,7 @@
  */
 
 #include <jit/compiler.h>
+#include <arch/instruction.h>
 #include <libharness.h>
 #include <vm/vm.h>
 
diff --git a/test/jit/spill-reload-test.c b/test/jit/spill-reload-test.c
index b09bee4..c686e46 100644
--- a/test/jit/spill-reload-test.c
+++ b/test/jit/spill-reload-test.c
@@ -26,6 +26,7 @@
 
 #include <jit/compilation-unit.h>
 #include <jit/compiler.h>
+#include <arch/instruction.h>
 #include <vm/vm.h>
 #include <libharness.h>
 
diff --git a/vm/class.c b/vm/class.c
index c0e1e61..9c0e5f6 100644
--- a/vm/class.c
+++ b/vm/class.c
@@ -27,6 +27,20 @@
 #include <vm/vm.h>
 #include <stdlib.h>
 
+struct object *create_null_pointer_exception()
+{
+       Class *exception = findSystemClass("java/lang/NullPointerException");
+       struct object *exp = allocObject(exception);
+       MethodBlock *init = lookupMethod(exception, "<init>",
+                                        "()V");
+       if(exp && init)
+               executeMethod(exp, init);
+       else
+               abort(); /* TODO */
+
+       return exp;
+}
+
 unsigned long is_object_instance_of(struct object *obj, struct object *type)
 {
        if (!obj)
diff --git a/vm/signal.c b/vm/signal.c
index 0ed393c..7eadd1e 100644
--- a/vm/signal.c
+++ b/vm/signal.c
@@ -24,12 +24,29 @@
  * Please refer to the file LICENSE for details.
  */
 
+#include <arch/signal.h>
+#include <arch/exception.h>
 #include <vm/backtrace.h>
+#include <vm/class.h>
 #include <stddef.h>
+#include <unistd.h>
 
-static void signal_handler(int sig, siginfo_t *si, void *unused)
+static void signal_handler(int sig, siginfo_t *si, void *ctx)
 {
-       print_backtrace_and_die(sig, si, unused);
+       /* Assume that zero-page access is caused by dereferencing a
+          null pointer */
+       if (sig == SIGSEGV && signal_from_jit_method(ctx) &&
+           ((int)si->si_addr < getpagesize())) {
+               struct object *exception;
+
+               /* TODO: stack trace for exception should be filled
+                  based on ctx. */
+               exception = create_null_pointer_exception();
+               throw_exception_from_signal(ctx, exception);
+               return;
+       }
+
+       print_backtrace_and_die(sig, si, ctx);
 }
 
 void setup_signal_handlers(void)
@@ -39,7 +56,7 @@ void setup_signal_handlers(void)
        sigemptyset(&sa.sa_mask);
        sa.sa_flags     = SA_RESTART | SA_SIGINFO;
        sa.sa_sigaction = signal_handler;
-   
+
        sigaction(SIGSEGV, &sa, NULL);
        sigaction(SIGUSR1, &sa, NULL);
 }
-- 
1.6.0.6


------------------------------------------------------------------------------
Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT
is a gathering of tech-side developers & brand creativity professionals. Meet
the minds behind Google Creative Lab, Visual Complexity, Processing, & 
iPhoneDevCamp asthey present alongside digital heavyweights like Barbarian
Group, R/GA, & Big Spaceship. http://www.creativitycat.com 
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to