Signed-off-by: Tomek Grabiec <[email protected]>
---
 arch/x86/Makefile_32                |    1 +
 arch/x86/emit-code_32.c             |   41 ++++++++++++---
 arch/x86/exception_32.c             |   10 +++-
 arch/x86/include/arch/emit-code.h   |    3 +-
 arch/x86/include/arch/exception.h   |    6 ++-
 arch/x86/include/arch/stack-frame.h |   12 ++++
 arch/x86/insn-selector_32.brg       |    2 +
 arch/x86/stack-frame.c              |   27 ++++++++++
 arch/x86/unwind_32.S                |   73 ++++++++++++++++++++++++++
 include/jit/compilation-unit.h      |    2 +
 include/jit/exception.h             |    8 +++
 jit/compilation-unit.c              |   11 ++++
 jit/emit.c                          |    3 +
 jit/exception.c                     |   98 +++++++++++++++++++++++++++++++++++
 scripts/build/test.mk               |    4 ++
 test/arch-mmix/stack-frame.c        |   32 +++++++++++
 test/arch-x86/Makefile              |    5 ++
 test/include/arch/exception.h       |   10 ++++
 test/include/arch/stack-frame.h     |    8 +++
 test/jamvm/thread-stub.c            |    8 +++
 test/jit/Makefile                   |    3 +
 21 files changed, 356 insertions(+), 11 deletions(-)
 create mode 100644 arch/x86/unwind_32.S
 create mode 100644 test/arch-mmix/stack-frame.c
 create mode 100644 test/include/arch/exception.h
 create mode 100644 test/jamvm/thread-stub.c

diff --git a/arch/x86/Makefile_32 b/arch/x86/Makefile_32
index c65c9f0..81bb5ad 100644
--- a/arch/x86/Makefile_32
+++ b/arch/x86/Makefile_32
@@ -8,6 +8,7 @@ ARCH_OBJS = \
        arch/x86/stack-frame.o          \
        arch/x86/use-def.o              \
        arch/x86/exception_32.o         \
+       arch/x86/unwind_32.o            \
        jamvm/os/$(OS)/i386/dll_md.o    \
        jamvm/os/$(OS)/i386/init.o      \
        jamvm/os/$(OS)/os.o
diff --git a/arch/x86/emit-code_32.c b/arch/x86/emit-code_32.c
index 97cc3fb..43ae427 100644
--- a/arch/x86/emit-code_32.c
+++ b/arch/x86/emit-code_32.c
@@ -11,6 +11,8 @@
 #include <jit/statement.h>
 #include <jit/compilation-unit.h>
 #include <jit/compiler.h>
+#include <jit/exception.h>
+#include <jit/stack-slot.h>
 
 #include <vm/list.h>
 #include <vm/buffer.h>
@@ -19,6 +21,7 @@
 #include <arch/emit-code.h>
 #include <arch/instruction.h>
 #include <arch/memory.h>
+#include <arch/exception.h>
 
 #include <assert.h>
 #include <errno.h>
@@ -27,6 +30,12 @@
 #include <stdbool.h>
 #include <string.h>
 
+#define PREFIX_SIZE 1
+#define BRANCH_INSN_SIZE 5
+#define BRANCH_TARGET_OFFSET 1
+
+#define CALL_INSN_SIZE 5
+
 /*
  *     __encode_reg:   Encode register to be used in IA-32 instruction.
  *     @reg: Register to encode.
@@ -431,8 +440,6 @@ static void emit_push_imm(struct buffer *buf, struct 
operand *operand)
        __emit_push_imm(buf, operand->imm);
 }
 
-#define CALL_INSN_SIZE 5
-
 static void __emit_call(struct buffer *buf, void *call_target)
 {
        int disp = call_target - buffer_current(buf) - CALL_INSN_SIZE;
@@ -451,7 +458,11 @@ void emit_ret(struct buffer *buf)
        emit(buf, 0xc3);
 }
 
-void emit_epilog(struct buffer *buf, unsigned long nr_locals)
+/*
+ * Emitted code must not write to ECX register because it may hold
+ * exception object reference when in unwind block
+ */
+static void __emit_epilog(struct buffer *buf, unsigned long nr_locals)
 {
        if (nr_locals)
                emit(buf, 0xc9);
@@ -462,10 +473,30 @@ void emit_epilog(struct buffer *buf, unsigned long 
nr_locals)
        __emit_pop_reg(buf, REG_EBX);
        __emit_pop_reg(buf, REG_ESI);
        __emit_pop_reg(buf, REG_EDI);
+}
 
+void emit_epilog(struct buffer *buf, unsigned long nr_locals)
+{
+       __emit_epilog(buf, nr_locals);
        emit_ret(buf);
 }
 
+static void __emit_jmp(struct buffer *buf, unsigned long addr)
+{
+       unsigned long current = (unsigned long)buffer_current(buf);
+       emit(buf, 0xE9);
+       emit_imm32(buf, addr - current - BRANCH_INSN_SIZE);
+}
+
+void emit_unwind(struct buffer *buf, unsigned long nr_locals)
+{
+       /* save exception object in ECX */
+       __emit_pop_reg(buf, REG_ECX);
+
+       __emit_epilog(buf, nr_locals);
+       __emit_jmp(buf, (unsigned long)&unwind);
+}
+
 static void emit_adc_reg_reg(struct buffer *buf,
                              struct operand *src, struct operand *dest)
 {
@@ -681,10 +712,6 @@ void emit_branch_rel(struct buffer *buf, unsigned char 
prefix,
        emit_imm32(buf, rel32);
 }
 
-#define PREFIX_SIZE 1
-#define BRANCH_INSN_SIZE 5
-#define BRANCH_TARGET_OFFSET 1
-
 static long branch_rel_addr(struct insn *insn, unsigned long target_offset)
 {
        long ret;
diff --git a/arch/x86/exception_32.c b/arch/x86/exception_32.c
index c703859..22e8028 100644
--- a/arch/x86/exception_32.c
+++ b/arch/x86/exception_32.c
@@ -24,9 +24,15 @@
  * Please refer to the file LICENSE for details.
  */
 
+#include <jit/exception.h>
 #include <arch/exception.h>
+#include <arch/stack-frame.h>
 
-unsigned char *throw_exception(struct object *exception)
+unsigned char *throw_exception(struct compilation_unit *cu,
+                              struct object *exception)
 {
-       return NULL; /* TODO */
+       unsigned char *native_ptr = __builtin_return_address(0) - 1;
+       struct jit_stack_frame *frame = __builtin_frame_address(1);
+
+       return throw_exception_from(cu, frame, native_ptr, exception);
 }
diff --git a/arch/x86/include/arch/emit-code.h 
b/arch/x86/include/arch/emit-code.h
index 52d1ef4..5ae5d93 100644
--- a/arch/x86/include/arch/emit-code.h
+++ b/arch/x86/include/arch/emit-code.h
@@ -10,5 +10,6 @@ void emit_prolog(struct buffer *, unsigned long);
 void emit_epilog(struct buffer *, unsigned long);
 void emit_body(struct basic_block *, struct buffer *);
 void emit_trampoline(struct compilation_unit *, void *, struct 
jit_trampoline*);
-    
+void emit_unwind(struct buffer *, unsigned long);
+
 #endif /* __X86_EMIT_CODE */
diff --git a/arch/x86/include/arch/exception.h 
b/arch/x86/include/arch/exception.h
index 422321e..1b52e6e 100644
--- a/arch/x86/include/arch/exception.h
+++ b/arch/x86/include/arch/exception.h
@@ -3,7 +3,11 @@
 
 #include <vm/vm.h>
 
+struct compilation_unit;
+
 /* This should be called only by JIT compiled native code */
-unsigned char *throw_exception(struct object *exception);
+unsigned char *throw_exception(struct compilation_unit *cu,
+                              struct object *exception);
+extern void unwind();
 
 #endif
diff --git a/arch/x86/include/arch/stack-frame.h 
b/arch/x86/include/arch/stack-frame.h
index ec1338a..1bb9e0f 100644
--- a/arch/x86/include/arch/stack-frame.h
+++ b/arch/x86/include/arch/stack-frame.h
@@ -5,9 +5,21 @@
 
 struct methodblock;
 struct expression;
+struct compilation_unit;
+
+struct jit_stack_frame {
+       struct jit_stack_frame *prev;
+       unsigned long old_ebx;
+       unsigned long old_esi;
+       unsigned long old_edi;
+       unsigned long return_address;
+       unsigned long args[0];
+} __attribute__((packed));
 
 unsigned long frame_local_offset(struct methodblock *, struct expression *);
 unsigned long slot_offset(struct stack_slot *slot);
 unsigned long frame_locals_size(struct stack_frame *frame);
+bool is_jit_method(unsigned long eip);
+unsigned long cu_frame_locals_offset(struct compilation_unit *cu);
 
 #endif
diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg
index c4d24ef..3bf0b6d 100644
--- a/arch/x86/insn-selector_32.brg
+++ b/arch/x86/insn-selector_32.brg
@@ -1105,7 +1105,9 @@ stmt:     STMT_ATHROW(reg)
        struct var_info *reg_eax = get_fixed_var(s->b_parent, REG_EAX);
 
        select_insn(s, tree, reg_insn(INSN_PUSH_REG, state->left->reg1));
+       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, (unsigned 
long)s->b_parent));
        select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned 
long)throw_exception));
+       method_args_cleanup(s, tree, 1);
 
        /* Jump where throw_exception() told us to jump */
        select_insn(s, tree, reg_insn(INSN_PUSH_REG, reg_eax));
diff --git a/arch/x86/stack-frame.c b/arch/x86/stack-frame.c
index cf1a612..b769932 100644
--- a/arch/x86/stack-frame.c
+++ b/arch/x86/stack-frame.c
@@ -25,6 +25,7 @@
  */
 
 #include <jit/expression.h>
+#include <jit/compilation-unit.h>
 #include <vm/vm.h>
 #include <arch/stack-frame.h>
 #include <stdlib.h>
@@ -90,3 +91,29 @@ unsigned long frame_locals_size(struct stack_frame *frame)
        unsigned long nr_locals = frame->nr_local_slots - frame->nr_args;
        return __index_to_offset(nr_locals + frame->nr_spill_slots);
 }
+
+/* Points to the first address past text segment */
+extern char etext;
+
+/*
+ * Checks whether address belongs to jitted or JATO method.
+ * This is used in deciding when to stop the unwind process upon
+ * exception throwing.
+ *
+ * It utilises the fact, that jitted code is allocated on heap. So by
+ * comparing return address with text segment end we can tell whether
+ * the caller is on heap or in text.
+ */
+bool is_jit_method(unsigned long eip)
+{
+       return eip >= (unsigned long)&etext;
+}
+
+/*
+ * Returns total offset to subtract from ESP to reserve space for locals.
+ */
+unsigned long cu_frame_locals_offset(struct compilation_unit *cu)
+{
+       unsigned long frame_size = frame_locals_size(cu->stack_frame);
+       return frame_size * sizeof(unsigned long);
+}
diff --git a/arch/x86/unwind_32.S b/arch/x86/unwind_32.S
new file mode 100644
index 0000000..a0cb68c
--- /dev/null
+++ b/arch/x86/unwind_32.S
@@ -0,0 +1,73 @@
+.global unwind
+.text
+
+/*
+ * unwind - Performs the following:
+ *          1) Resets the stack pointer to point at the end of
+ *             caller's stack frame
+ *          2) Rethrows the exception in caller's context
+ */
+unwind:
+       popl %edx         /* method's return address */
+       decl %edx
+
+       /*
+        * Get compilation unit
+        */
+       push %ecx
+       push %edx
+       call get_cu_from_native_addr
+       pop %edx
+       pop %ecx
+
+       /*
+        * Restore stack pointer.
+        * We need to restore space for locals too.
+        */
+       push %ecx
+       push %edx
+
+       push %eax
+       call cu_frame_locals_offset
+       addl $4, %esp
+
+       pop %edx
+       pop %ecx
+
+       movl %ebp, %esp
+       subl %eax, %esp
+
+       /*
+        * Get compilation unit
+        */
+       push %ecx
+       push %edx
+       call get_cu_from_native_addr
+       pop %edx
+       pop %ecx
+
+       pushl %ecx /* push exception object reference to handler */
+
+       /*
+        * throw_exception_from(frame, native_ptr, exception);
+        */
+       pushl %ecx
+       pushl %edx
+       pushl %ebp
+       pushl %eax
+       call throw_exception_from
+       popl %ecx /* cu -> ECX */
+       addl $12, %esp
+
+       test %eax,%eax
+       jnz finish
+
+       /* Jump to exit block. Do not push exception object */
+       add $4, %esp
+       pushl %ecx
+       call cu_exit_bb_native_ptr
+       addl $4, %esp
+
+finish:
+       pushl %eax
+       ret
diff --git a/include/jit/compilation-unit.h b/include/jit/compilation-unit.h
index 9de65d7..2c5e0b3 100644
--- a/include/jit/compilation-unit.h
+++ b/include/jit/compilation-unit.h
@@ -18,6 +18,7 @@ struct compilation_unit {
        struct methodblock *method;
        struct list_head bb_list;
        struct basic_block *exit_bb;
+       struct basic_block *unwind_bb;
        struct var_info *var_infos;
        unsigned long nr_vregs;
        struct buffer *objcode;
@@ -44,6 +45,7 @@ struct basic_block *find_bb(struct compilation_unit *, 
unsigned long);
 unsigned long nr_bblocks(struct compilation_unit *);
 void compute_insn_positions(struct compilation_unit *);
 int sort_basic_blocks(struct compilation_unit *);
+unsigned char *cu_exit_bb_native_ptr(struct compilation_unit *);
 
 #define for_each_variable(var, var_list) for (var = var_list; var != NULL; var 
= var->next)
 
diff --git a/include/jit/exception.h b/include/jit/exception.h
index 6ea47f0..dbbc18b 100644
--- a/include/jit/exception.h
+++ b/include/jit/exception.h
@@ -3,6 +3,9 @@
 
 #include <jit/compilation-unit.h>
 #include <vm/vm.h>
+#include <arch/stack-frame.h>
+
+struct jit_stack_frame;
 
 struct exception_table_entry *exception_find_entry(struct methodblock *,
                                                   unsigned long);
@@ -13,4 +16,9 @@ static inline bool exception_covers(struct 
exception_table_entry *eh,
        return eh->start_pc <= offset && offset < eh->end_pc;
 }
 
+unsigned char *throw_exception_from(struct compilation_unit *cu,
+                                   struct jit_stack_frame *frame,
+                                   unsigned char *native_ptr,
+                                   struct object *exception);
+
 #endif
diff --git a/jit/compilation-unit.c b/jit/compilation-unit.c
index 0848f69..652ea7c 100644
--- a/jit/compilation-unit.c
+++ b/jit/compilation-unit.c
@@ -46,6 +46,11 @@ struct compilation_unit *alloc_compilation_unit(struct 
methodblock *method)
                cu->exit_bb = alloc_basic_block(cu, 0, 0);
                if (!cu->exit_bb)
                        goto out_of_memory;
+
+               cu->unwind_bb = alloc_basic_block(cu, 0, 0);
+               if (!cu->unwind_bb)
+                       goto out_of_memory;
+
                pthread_mutex_init(&cu->mutex, NULL);
                cu->stack_frame = alloc_stack_frame(method->args_count,
                                                    method->max_locals);
@@ -84,6 +89,7 @@ void free_compilation_unit(struct compilation_unit *cu)
 
        pthread_mutex_destroy(&cu->mutex);
        free_basic_block(cu->exit_bb);
+       free_basic_block(cu->unwind_bb);
        free_buffer(cu->objcode);
        free_var_infos(cu->var_infos);
        free_stack_frame(cu->stack_frame);
@@ -179,3 +185,8 @@ int sort_basic_blocks(struct compilation_unit *cu)
 {
        return list_sort(&cu->bb_list, bb_list_compare);
 }
+
+unsigned char *cu_exit_bb_native_ptr(struct compilation_unit *cu)
+{
+       return bb_native_ptr(cu->exit_bb);
+}
diff --git a/jit/emit.c b/jit/emit.c
index 1c8af96..22ab463 100644
--- a/jit/emit.c
+++ b/jit/emit.c
@@ -44,6 +44,9 @@ int emit_machine_code(struct compilation_unit *cu)
        emit_body(cu->exit_bb, cu->objcode);
        emit_epilog(cu->objcode, frame_size);
 
+       emit_body(cu->unwind_bb, cu->objcode);
+       emit_unwind(cu->objcode, frame_size);
+
        return 0;
 }
 
diff --git a/jit/exception.c b/jit/exception.c
index b3d3dd5..2a98dab 100644
--- a/jit/exception.c
+++ b/jit/exception.c
@@ -26,6 +26,10 @@
 
 #include <jit/exception.h>
 #include <jit/compilation-unit.h>
+#include <jit/bc-offset-mapping.h>
+#include <vm/buffer.h>
+#include <arch/exception.h>
+#include <arch/stack-frame.h>
 
 struct exception_table_entry *exception_find_entry(struct methodblock *method,
                                                   unsigned long target)
@@ -41,3 +45,97 @@ struct exception_table_entry *exception_find_entry(struct 
methodblock *method,
 
        return NULL;
 }
+
+static unsigned char *eh_native_ptr(struct compilation_unit *cu,
+                                   struct exception_table_entry *eh)
+{
+       struct basic_block *bb = find_bb(cu, eh->handler_pc);
+
+       assert(bb != NULL);
+
+       return bb_native_ptr(bb);
+}
+
+/**
+ * find_handler - return native pointer to exception handler for given
+ *                @exception_class and @bc_offset of source.
+ */
+static unsigned char *find_handler(struct compilation_unit *cu,
+                                  Class *exception_class,
+                                  unsigned long bc_offset)
+{
+       struct exception_table_entry *eh;
+       struct methodblock *method = cu->method;
+       int size = method->exception_table_size;
+       int i;
+
+       for (i = 0; i < size; i++) {
+               eh = &method->exception_table[i];
+
+               if (exception_covers(eh, bc_offset)) {
+                       Class *catch_class;
+
+                       if (eh->catch_type == 0)
+                               break; /* It's a finally block */
+
+                       catch_class = resolveClass(method->class,
+                                                  eh->catch_type,
+                                                  false);
+
+                       if (isInstanceOf(catch_class, exception_class))
+                               break;
+               }
+       }
+
+       if (i < size)
+               return eh_native_ptr(cu, eh);
+
+       return NULL;
+}
+
+/**
+ * throw_exception_from - returns native pointer inside jitted method
+ *                        that sould be executed to handle exception.
+ *                        This can be one of the following:
+ *                        1) registered exception handler (catch/finally block)
+ *                        2) method's unwind block (when no handler is found)
+ *                        3) method's exit block (when no handler is found and
+ *                           unwind can't be done because the method's caller
+ *                           is not a jitted method).
+ *
+ * @frame: frame pointer of method throwing exception
+ * @native_ptr: pointer to instruction that caused exception
+ * @exception: exception object to throw.
+ */
+unsigned char *throw_exception_from(struct compilation_unit *cu,
+                                   struct jit_stack_frame *frame,
+                                   unsigned char *native_ptr,
+                                   struct object *exception)
+{
+       unsigned char *eh_ptr = NULL;
+       unsigned long bc_offset;
+
+       if (getExecEnv()->exception != NULL) {
+               /* Looks like we've caught some asynchronous exception,
+                  which must have precedence. */
+               exception = getExecEnv()->exception;
+               getExecEnv()->exception = NULL;
+       }
+
+       bc_offset = native_ptr_to_bytecode_offset(cu, native_ptr);
+       if (bc_offset != BC_OFFSET_UNKNOWN) {
+               eh_ptr = find_handler(cu, exception->class, bc_offset);
+               if (eh_ptr != NULL)
+                       return eh_ptr;
+       }
+
+       if (!is_jit_method(frame->return_address)) {
+               /* No handler found within jitted method call
+                  chain. Signal exception and return to previous
+                  (non-jitted) method. */
+               getExecEnv()->exception = exception;
+               return NULL;
+       }
+
+       return bb_native_ptr(cu->unwind_bb);
+}
diff --git a/scripts/build/test.mk b/scripts/build/test.mk
index e3f1b1a..a4afcdb 100644
--- a/scripts/build/test.mk
+++ b/scripts/build/test.mk
@@ -14,6 +14,10 @@ endif
        $(E) "  CC      " $@
        $(Q) $(CC) $(ARCH_CFLAGS) $(DEFAULT_CFLAGS) $(CFLAGS) $(INCLUDE) 
$(DEFINES) -c $< -o `basename $...@`
 
+%.o: %.S
+       $(E) "  AS      " $@
+       $(Q) $(AS) $(AFLAGS) $< -o `basename $...@`
+
 test: $(RUNNER)
 
 $(RUNNER): $(SUITE) $(OBJS)
diff --git a/test/arch-mmix/stack-frame.c b/test/arch-mmix/stack-frame.c
new file mode 100644
index 0000000..78021db
--- /dev/null
+++ b/test/arch-mmix/stack-frame.c
@@ -0,0 +1,32 @@
+/*
+ * 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/stack-frame.h>
+
+bool is_jit_method(unsigned long eip)
+{
+       return false;
+}
diff --git a/test/arch-x86/Makefile b/test/arch-x86/Makefile
index 8e3b6ad..c8b4227 100644
--- a/test/arch-x86/Makefile
+++ b/test/arch-x86/Makefile
@@ -24,6 +24,8 @@ OBJS = \
        ../jamvm/alloc-stub.o \
        ../jamvm/cast-stub.o \
        ../jamvm/lock.o \
+       ../jamvm/thread-stub.o \
+       ../jamvm/resolve-stub.o \
        ../../arch/x86/backtrace.o \
        ../../vm/buffer.o \
        ../../vm/list.o \
@@ -44,12 +46,15 @@ OBJS = \
        ../../jit/tree-printer.o \
        ../../jit/fixup-site.o \
        ../../jit/bc-offset-mapping.o \
+       ../../jit/exception.o \
+       ../../jit/cu-mapping.o \
        ../../arch/x86/emit-code$(ARCH_POSTFIX).o \
        ../../arch/x86/instruction.o \
        ../../arch/x86/insn-selector$(ARCH_POSTFIX).o \
        ../../arch/x86/stack-frame.o \
        ../../arch/x86/use-def.o \
        ../../arch/x86/exception$(ARCH_POSTFIX).o \
+       ../../arch/x86/unwind$(ARCH_POSTFIX).o \
        $(TESTS)
 
 TESTS = \
diff --git a/test/include/arch/exception.h b/test/include/arch/exception.h
new file mode 100644
index 0000000..dc2a743
--- /dev/null
+++ b/test/include/arch/exception.h
@@ -0,0 +1,10 @@
+#ifndef __ARCH_EXCEPTION_H
+#define __ARCH_EXCEPTION_H
+
+struct object;
+struct compilation_unit;
+
+unsigned char *throw_exception(struct compilation_unit *cu,
+                              struct object *exception);
+
+#endif /* __ARCH_EXCEPTION_H */
diff --git a/test/include/arch/stack-frame.h b/test/include/arch/stack-frame.h
index 946ac33..1cdbc2d 100644
--- a/test/include/arch/stack-frame.h
+++ b/test/include/arch/stack-frame.h
@@ -1,4 +1,12 @@
 #ifndef MMIX_STACK_FRAME_H
 #define MMIX_STACK_FRAME_H
 
+#include <stdbool.h>
+
+struct jit_stack_frame {
+       unsigned long return_address;
+};
+
+bool is_jit_method(unsigned long eip);
+
 #endif /* MMIX_STACK_FRAME_H */
diff --git a/test/jamvm/thread-stub.c b/test/jamvm/thread-stub.c
new file mode 100644
index 0000000..8eeb0aa
--- /dev/null
+++ b/test/jamvm/thread-stub.c
@@ -0,0 +1,8 @@
+#include <vm/vm.h>
+
+ExecEnv *getExecEnv()
+{
+       static ExecEnv ee;
+
+       return &ee;
+}
diff --git a/test/jit/Makefile b/test/jit/Makefile
index 3ec6fd4..efd9842 100644
--- a/test/jit/Makefile
+++ b/test/jit/Makefile
@@ -39,8 +39,11 @@ OBJS = \
        ../libharness/libharness.o \
        ../jamvm/alloc-stub.o \
        ../jamvm/resolve-stub.o \
+       ../jamvm/thread-stub.o \
+       ../jamvm/cast-stub.o \
        ../arch-mmix/instruction.o \
        ../arch-mmix/use-def.o \
+       ../arch-mmix/stack-frame.o \
        arithmetic-bc-test.o \
        basic-block-test.o \
        bc-test-utils.o \
-- 
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