This significantly reduces code required for doing null checks. 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 | 22 +++++++++++++++ arch/x86/insn-selector_32.brg | 5 +--- arch/x86/signal.c | 47 +++++++++++++++++++++++++++++++++ test/arch-x86/insn-selector-test_32.c | 8 +----- vm/signal.c | 39 ++++++++++++++++++++++++--- 8 files changed, 144 insertions(+), 15 deletions(-) create mode 100644 arch/x86/include/arch/signal.h create mode 100644 arch/x86/signal.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..f3e5612 100644 --- a/arch/x86/exception_32.c +++ b/arch/x86/exception_32.c @@ -25,8 +25,13 @@ */ #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> +#include <arch/signal.h> unsigned char *throw_exception(struct compilation_unit *cu, struct object *exception) @@ -36,3 +41,34 @@ 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 *uc; + struct jit_stack_frame *frame; + struct compilation_unit *cu; + unsigned long source_addr; + void *eh; + + uc = ctx; + + source_addr = uc->uc_mcontext.gregs[REG_IP]; + cu = get_cu_from_native_addr(source_addr); + frame = (struct jit_stack_frame*)uc->uc_mcontext.gregs[REG_BP]; + + eh = throw_exception_from(cu, frame, (unsigned char*)source_addr, + exception); + + if (eh == NULL) { + uc->uc_mcontext.gregs[REG_IP] = (unsigned long)bb_native_ptr(cu->exit_bb); + } else { + unsigned long *stack; + + uc->uc_mcontext.gregs[REG_IP] = (unsigned long)eh; + + /* push exception object reference on stack */ + uc->uc_mcontext.gregs[REG_SP] -= sizeof(exception); + stack = (unsigned long*)uc->uc_mcontext.gregs[REG_SP]; + *stack = (unsigned long)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..49ce51f --- /dev/null +++ b/arch/x86/include/arch/signal.h @@ -0,0 +1,22 @@ +#ifndef _ARCH_SIGNAL_H +#define _ARCH_SIGNAL_H + +#include <stdbool.h> +#include <stdlib.h> +#include <ucontext.h> + +#ifdef CONFIG_X86_32 + #define REG_IP REG_EIP + #define REG_SP REG_ESP + #define REG_BP REG_EBP +#elif defined(CONFIG_X86_64) + #define REG_IP REG_RIP + #define REG_SP REG_RSP + #define REG_BP REG_RBP +#else + #error Unsupported architecture +#endif + +bool signal_from_jit_method(void *ctx); + +#endif diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg index af95758..7ba99c4 100644 --- a/arch/x86/insn-selector_32.brg +++ b/arch/x86/insn-selector_32.brg @@ -1121,10 +1121,7 @@ stmt: STMT_NULL_CHECK(reg) ref = state->left->reg1; - select_insn(s, tree, reg_insn(INSN_PUSH_REG, ref)); - select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) check_null)); - - method_args_cleanup(s, tree, 1); + select_insn(s, tree, membase_reg_insn(INSN_TEST_MEMBASE_REG, ref, 0, ref)); } array_check: EXPR_ARRAY_DEREF(reg, reg) 2 diff --git a/arch/x86/signal.c b/arch/x86/signal.c new file mode 100644 index 0000000..fd3c260 --- /dev/null +++ b/arch/x86/signal.c @@ -0,0 +1,47 @@ +/* + * 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 <arch/signal.h> +#include <arch/stack-frame.h> +#include <jit/cu-mapping.h> + +bool signal_from_jit_method(void *ctx) +{ + ucontext_t *uc; + unsigned long ip; + + uc = ctx; + ip = uc->uc_mcontext.gregs[REG_IP]; + + if (!is_jit_method(ip)) + return false; + + /* We must be extra caucious here because IP might be iinvalid*/ + if (get_cu_from_native_addr(ip) == NULL) + return false; + + return true; +} diff --git a/test/arch-x86/insn-selector-test_32.c b/test/arch-x86/insn-selector-test_32.c index d490042..db43765 100644 --- a/test/arch-x86/insn-selector-test_32.c +++ b/test/arch-x86/insn-selector-test_32.c @@ -1509,13 +1509,7 @@ void test_select_null_check_stmt(void) assert_imm_reg_insn(INSN_MOV_IMM_REG, 0xcafebabe, dreg1, insn); insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_reg_insn(INSN_PUSH_REG, dreg1, insn); - - insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_rel_insn(INSN_CALL_REL, (unsigned long) check_null, insn); - - insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_imm_reg_insn(INSN_ADD_IMM_REG, 4, REG_ESP, insn); + assert_membase_reg_insn(INSN_TEST_MEMBASE_REG, dreg1, 0, dreg1, insn); free_compilation_unit(cu); } diff --git a/vm/signal.c b/vm/signal.c index 0ed393c..c8fa535 100644 --- a/vm/signal.c +++ b/vm/signal.c @@ -24,12 +24,41 @@ * 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> +#include <ucontext.h> -static void signal_handler(int sig, siginfo_t *si, void *unused) +static void sigsegv_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 (signal_from_jit_method(ctx) && + ((unsigned long)si->si_addr < (unsigned long)getpagesize())) { + struct object *exception; + + /* TODO: exception's stack trace should be filled using ctx */ + exception = create_object("java/lang/NullPointerException"); + if (exception == NULL) { + /* TODO: throw OutOfMemoryError */ + fprintf(stderr, "%s: Out of memory\n", __FUNCTION__); + goto exit; + } + + throw_exception_from_signal(ctx, exception); + return; + } + + exit: + print_backtrace_and_die(sig, si, ctx); +} + +static void signal_handler(int sig, siginfo_t *si, void *ctx) +{ + print_backtrace_and_die(sig, si, ctx); } void setup_signal_handlers(void) @@ -38,8 +67,10 @@ void setup_signal_handlers(void) sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_SIGINFO; - sa.sa_sigaction = signal_handler; - + + sa.sa_sigaction = sigsegv_handler; sigaction(SIGSEGV, &sa, NULL); + + sa.sa_sigaction = signal_handler; 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