This implements emit_trampoline() and related emitters and fixes code
that it depends on.

Signed-off-by: Eduard - Gabriel Munteanu <eduard.munte...@linux360.ro>
---
 arch/x86/Makefile_64                |    1 +
 arch/x86/emit-code.c                |  205 +++++++++++++++++++++++++++++++++--
 arch/x86/include/arch/instruction.h |    4 +
 arch/x86/thread.c                   |    8 +-
 4 files changed, 204 insertions(+), 14 deletions(-)

diff --git a/arch/x86/Makefile_64 b/arch/x86/Makefile_64
index c12328a..7096e51 100644
--- a/arch/x86/Makefile_64
+++ b/arch/x86/Makefile_64
@@ -13,5 +13,6 @@ ARCH_OBJS = \
        arch/x86/signal.o               \
        arch/x86/signal-bh.o            \
        arch/x86/stack-frame.o          \
+       arch/x86/thread.o               \
        arch/x86/use-def.o              \
        arch/x86/unwind_64.o
diff --git a/arch/x86/emit-code.c b/arch/x86/emit-code.c
index 60fbe48..6515624 100644
--- a/arch/x86/emit-code.c
+++ b/arch/x86/emit-code.c
@@ -38,11 +38,12 @@
 
 /* Aliases and prototypes to make common emitters work as expected. */
 #ifdef CONFIG_X86_64
-# define __emit_add_imm_reg    __emit64_add_imm_reg
-# define __emit_pop_reg                __emit64_pop_reg
-# define __emit_push_imm       __emit64_push_imm
-# define __emit_push_membase   __emit64_push_membase
-# define __emit_push_reg       __emit64_push_reg
+# define __emit_add_imm_reg            __emit64_add_imm_reg
+# define __emit_pop_reg                        __emit64_pop_reg
+# define __emit_push_imm               __emit64_push_imm
+# define __emit_push_membase           __emit64_push_membase
+# define __emit_push_reg               __emit64_push_reg
+# define __emit_mov_reg_reg            __emit64_mov_reg_reg
 #endif
 
 static unsigned char __encode_reg(enum machine_reg reg);
@@ -55,6 +56,10 @@ static void __emit_push_membase(struct buffer *buf,
                                enum machine_reg src_reg,
                                unsigned long disp);
 static void __emit_push_reg(struct buffer *buf, enum machine_reg reg);
+static void __emit_mov_reg_reg(struct buffer *buf,
+                              enum machine_reg src,
+                              enum machine_reg dst);
+static void emit_indirect_jump_reg(struct buffer *buf, enum machine_reg reg);
 static void emit_exception_test(struct buffer *buf, enum machine_reg reg);
 static void emit_restore_regs(struct buffer *buf);
 
@@ -1572,6 +1577,13 @@ static inline unsigned char reg_high(unsigned char reg)
        return (reg & 0x8);
 }
 
+static inline unsigned long rip_relative(struct buffer *buf,
+                                        unsigned long addr,
+                                        unsigned long insn_size)
+{
+       return addr - (unsigned long) buffer_current(buf) - insn_size;
+}
+
 static void __emit_reg(struct buffer *buf,
                       int rex_w,
                       unsigned char opc,
@@ -1762,10 +1774,10 @@ static void emit32_add_imm_reg(struct buffer *buf,
        __emit64_add_imm_reg(buf, src->imm, mach_reg(&dest->reg));
 }
 
-static void emit_imm64(struct buffer *buf, int imm)
+static void emit_imm64(struct buffer *buf, unsigned long imm)
 {
        union {
-               int val;
+               unsigned long val;
                unsigned char b[8];
        } imm_buf;
 
@@ -1853,6 +1865,32 @@ static void __emit_membase(struct buffer *buf,
                emit_imm(buf, disp);
 }
 
+static void __emit_membase_reg(struct buffer *buf,
+                              int rex_w,
+                              unsigned char opc,
+                              enum machine_reg base_reg,
+                              unsigned long disp,
+                              enum machine_reg dest_reg)
+{
+       __emit_membase(buf, rex_w, opc, base_reg, disp, __encode_reg(dest_reg));
+}
+
+static void emit_membase_reg(struct buffer *buf,
+                            int rex_w,
+                            unsigned char opc,
+                            struct operand *src,
+                            struct operand *dest)
+{
+       enum machine_reg base_reg, dest_reg;
+       unsigned long disp;
+
+       base_reg = mach_reg(&src->base_reg);
+       disp = src->disp;
+       dest_reg = mach_reg(&dest->reg);
+
+       __emit_membase_reg(buf, rex_w, opc, base_reg, disp, dest_reg);
+}
+
 static void __emit64_push_membase(struct buffer *buf,
                                  enum machine_reg src_reg,
                                  unsigned long disp)
@@ -1865,19 +1903,127 @@ static void emit_exception_test(struct buffer *buf, 
enum machine_reg reg)
        /* FIXME: implement this! */
 }
 
+static void __emit_memdisp(struct buffer *buf,
+                          int rex_w,
+                          unsigned char opc,
+                          unsigned long disp,
+                          unsigned char reg_opcode)
+{
+       unsigned char rex_pfx = 0, mod_rm;
+       size_t insn_size = 6;
+
+       if (rex_w)
+               rex_pfx |= REX_W;
+       if (reg_high(reg_opcode))
+               rex_pfx |= REX_R;
+
+       mod_rm = encode_modrm(0, reg_opcode, 5);
+
+       if (rex_pfx) {
+               emit(buf, rex_pfx);
+               insn_size++;
+       }
+       emit(buf, opc);
+       emit(buf, mod_rm);
+       emit_imm32(buf, rip_relative(buf, disp, insn_size));
+}
+
+static void __emit_memdisp_reg(struct buffer *buf,
+                              int rex_w,
+                              unsigned char opc,
+                              unsigned long disp,
+                              enum machine_reg reg)
+{
+       __emit_memdisp(buf, rex_w, opc, disp, __encode_reg(reg));
+}
+
+static void __emit64_test_membase_reg(struct buffer *buf,
+                                     enum machine_reg src,
+                                     unsigned long disp,
+                                     enum machine_reg dest)
+{
+       __emit_membase_reg(buf, 1, 0x85, src, disp, dest);
+}
+
+static void __emit32_test_membase_reg(struct buffer *buf,
+                                     enum machine_reg src,
+                                     unsigned long disp,
+                                     enum machine_reg dest)
+{
+       __emit_membase_reg(buf, 0, 0x85, src, disp, dest);
+}
+
+static void emit64_test_membase_reg(struct buffer *buf,
+                                   struct operand *src,
+                                   struct operand *dest)
+{
+       emit_membase_reg(buf, 1, 0x85, src, dest);
+}
+
+static void emit32_test_membase_reg(struct buffer *buf,
+                                   struct operand *src,
+                                   struct operand *dest)
+{
+       emit_membase_reg(buf, 0, 0x85, src, dest);
+}
+
+static void emit_indirect_jump_reg(struct buffer *buf, enum machine_reg reg)
+{
+       unsigned char __reg = __encode_reg(reg);
+
+       emit(buf, 0xff);
+       if (reg_high(__reg))
+               emit(buf, REX_B);
+       emit(buf, encode_modrm(0x3, 0x04, __reg));
+}
+
+static void __emit64_mov_imm_reg(struct buffer *buf,
+                                long imm,
+                                enum machine_reg reg)
+{
+       __emit_reg(buf, 1, 0xb8, reg);
+       emit_imm64(buf, imm);
+}
+
+static void emit64_mov_imm_reg(struct buffer *buf,
+                              struct operand *src,
+                              struct operand *dest)
+{
+       __emit64_mov_imm_reg(buf, src->imm, mach_reg(&dest->reg));
+}
+
+static void __emit64_mov_membase_reg(struct buffer *buf,
+                                    enum machine_reg base_reg,
+                                    unsigned long disp,
+                                    enum machine_reg dest_reg)
+{
+       __emit_membase_reg(buf, 1, 0x8b, base_reg, disp, dest_reg);
+}
+
+static void emit64_mov_membase_reg(struct buffer *buf,
+                                  struct operand *src,
+                                  struct operand *dest)
+{
+       emit_membase_reg(buf, 1, 0x8b, src, dest);
+}
+
 struct emitter emitters[] = {
        GENERIC_X86_EMITTERS,
 
        DECL_EMITTER(INSN64_ADD_IMM_REG, emit64_add_imm_reg, TWO_OPERANDS),
+       DECL_EMITTER(INSN64_MOV_IMM_REG, emit64_mov_imm_reg, TWO_OPERANDS),
+       DECL_EMITTER(INSN64_MOV_MEMBASE_REG, emit64_mov_membase_reg, 
TWO_OPERANDS),
        DECL_EMITTER(INSN64_MOV_REG_REG, emit64_mov_reg_reg, TWO_OPERANDS),
        DECL_EMITTER(INSN64_PUSH_IMM, emit64_push_imm, SINGLE_OPERAND),
        DECL_EMITTER(INSN64_PUSH_REG, emit64_push_reg, SINGLE_OPERAND),
        DECL_EMITTER(INSN64_POP_REG, emit64_pop_reg, SINGLE_OPERAND),
        DECL_EMITTER(INSN64_SUB_IMM_REG, emit64_sub_imm_reg, TWO_OPERANDS),
+       DECL_EMITTER(INSN64_TEST_MEMBASE_REG, emit64_test_membase_reg, 
TWO_OPERANDS),
 
        DECL_EMITTER(INSN32_ADD_IMM_REG, emit32_add_imm_reg, TWO_OPERANDS),
        DECL_EMITTER(INSN32_MOV_REG_REG, emit32_mov_reg_reg, TWO_OPERANDS),
        DECL_EMITTER(INSN32_SUB_IMM_REG, emit32_sub_imm_reg, TWO_OPERANDS),
+       DECL_EMITTER(INSN32_TEST_MEMBASE_REG, emit64_test_membase_reg, 
TWO_OPERANDS),
 };
 
 void emit_prolog(struct buffer *buf, unsigned long nr_locals)
@@ -1912,10 +2058,51 @@ static void emit_restore_regs(struct buffer *buf)
        __emit_pop_reg(buf, REG_RBX);
 }
 
-void emit_trampoline(struct compilation_unit *cu, void *call_target,
+void emit_trampoline(struct compilation_unit *cu,
+                    void *call_target,
                     struct jit_trampoline *trampoline)
 {
-       abort();
+       struct buffer *buf = trampoline->objcode;
+
+       jit_text_lock();
+
+       buf->buf = jit_text_ptr();
+
+       /* This is for __builtin_return_address() to work and to access
+          call arguments in correct manner. */
+       __emit64_push_reg(buf, REG_RBP);
+       __emit64_mov_reg_reg(buf, REG_RSP, REG_RBP);
+
+       __emit64_mov_imm_reg(buf, (unsigned long) cu, REG_RDI);
+       __emit_call(buf, call_target);
+
+       /*
+        * Test for exception occurance.
+        * We do this by polling a dedicated thread-specific pointer,
+        * which triggers SIGSEGV when exception is set.
+        *
+        * mov fs:(0xXXX), %rcx
+        * test (%rcx), %rcx
+        */
+       emit(buf, 0x64);
+       __emit_memdisp_reg(buf, 1, 0x8b,
+                          get_thread_local_offset(&trampoline_exception_guard),
+                          REG_RCX);
+       __emit64_test_membase_reg(buf, REG_RCX, 0, REG_RCX);
+
+       __emit64_mov_reg_reg(buf, REG_RAX, REG_RDI);
+
+       if (method_is_virtual(cu->method)) {
+               __emit64_mov_membase_reg(buf, REG_RBP, 0x08, REG_RSI);
+               __emit64_mov_imm_reg(buf, (unsigned long) cu, REG_RDX);
+               __emit_call(buf, fixup_vtable);
+       }
+
+       __emit64_pop_reg(buf, REG_RBP);
+       emit_indirect_jump_reg(buf, REG_RDX);
+
+       jit_text_reserve(buffer_offset(buf));
+       jit_text_unlock();
 }
 
 #endif /* CONFIG_X86_32 */
diff --git a/arch/x86/include/arch/instruction.h 
b/arch/x86/include/arch/instruction.h
index 86f0141..b3c6f42 100644
--- a/arch/x86/include/arch/instruction.h
+++ b/arch/x86/include/arch/instruction.h
@@ -132,11 +132,14 @@ enum insn_type {
 
 #ifdef CONFIG_X86_64
        INSN64_ADD_IMM_REG,
+       INSN64_MOV_IMM_REG,
+       INSN64_MOV_MEMBASE_REG,
        INSN64_MOV_REG_REG,
        INSN64_PUSH_IMM,
        INSN64_PUSH_REG,
        INSN64_POP_REG,
        INSN64_SUB_IMM_REG,
+       INSN64_TEST_MEMBASE_REG,
 
        INSN32_ADD_IMM_REG,
        INSN32_MOV_REG_REG,
@@ -144,6 +147,7 @@ enum insn_type {
        INSN32_PUSH_REG,
        INSN32_POP_REG,
        INSN32_SUB_IMM_REG,
+       INSN32_TEST_MEMBASE_REG,
 
        /* Aliases for instructions in common code. */
        INSN64_CALL_REL         = INSN_CALL_REL,
diff --git a/arch/x86/thread.c b/arch/x86/thread.c
index 2eeaf01..e715410 100644
--- a/arch/x86/thread.c
+++ b/arch/x86/thread.c
@@ -35,7 +35,9 @@ static unsigned long get_tls_address(void)
                "movl %%gs:(0x0), %0 \n"
                : "=r"(result) );
 #else
- #error not implemented
+       __asm__(
+               "movq %%fs:(0x0), %0 \n"
+               : "=r"(result) );
 #endif
 
        return result;
@@ -43,9 +45,5 @@ static unsigned long get_tls_address(void)
 
 unsigned long get_thread_local_offset(void *thread_local_ptr)
 {
-#ifdef CONFIG_X86_32
        return (unsigned long)thread_local_ptr - get_tls_address();
-#else
- #error not implemented
-#endif
 }
-- 
1.6.0.6


------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge  
This is your chance to win up to $100,000 in prizes! For a limited time, 
vendors submitting new applications to BlackBerry App World(TM) will have 
the opportunity to enter the BlackBerry Developer Challenge. See full prize 
details at: http://p.sf.net/sfu/blackberry
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to