2004-06-10 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mono / mini / tramp-sparc.c
index 32e305690d2e7425708f619b5aba93bdb2e4c538..e55230e3b7af23336d8e086cbb824468124e06cd 100644 (file)
@@ -72,6 +72,7 @@ get_unbox_trampoline (MonoMethod *m, gpointer addr)
  * sparc_magic_trampoline:
  * @m: the method to translate
  * @code: the address of the call instruction
+ * @fp: address of the stack frame for the caller
  *
  * This method is called by the trampoline functions for methods. It calls the
  * JIT compiler to compile the method, then patches the calling instruction so
@@ -79,15 +80,14 @@ get_unbox_trampoline (MonoMethod *m, gpointer addr)
  * address of the vtable slot and updates it.
  */
 static gpointer
-sparc_magic_trampoline (MonoMethod *m, guint32 *code)
+sparc_magic_trampoline (MonoMethod *m, guint32 *code, guint32 *fp)
 {
        gpointer addr;
+       gpointer *vtable_slot;
 
        addr = mono_compile_method (m);
        g_assert (addr);
 
-       /* FIXME: patch calling code and vtable */
-
        /*
         * Check whenever this is a virtual call, and call an unbox trampoline if
         * needed.
@@ -95,6 +95,15 @@ sparc_magic_trampoline (MonoMethod *m, guint32 *code)
        if (mono_sparc_is_virtual_call (code)) {
                if (m->klass->valuetype)
                        addr = get_unbox_trampoline (m, addr);
+
+               /* Compute address of vtable slot */
+               vtable_slot = mono_sparc_get_vcall_slot_addr (code, fp);
+               *vtable_slot = addr;
+       }
+       else {
+               /* Patch calling code */
+               if (sparc_inst_op (*code) == 0x1)
+                       sparc_call_simple (code, (guint8*)addr - (guint8*)code);
        }
 
        return addr;
@@ -105,13 +114,15 @@ sparc_class_init_trampoline (MonoVTable *vtable, guint32 *code)
 {
        mono_runtime_class_init (vtable);
 
-       /* FIXME: patch calling code */
+       /* Patch calling code */
+       sparc_nop (code);
 }
 
 static guchar*
 create_trampoline_code (MonoTrampolineType tramp_type)
 {
        guint8 *buf, *code, *tramp_addr;
+       guint32 lmf_offset;
        static guint8* generic_jump_trampoline = NULL;
        static guint8 *generic_class_init_trampoline = NULL;
 
@@ -136,17 +147,51 @@ create_trampoline_code (MonoTrampolineType tramp_type)
 
        sparc_save_imm (code, sparc_sp, -200, sparc_sp);
 
-       /* We receive the method address in %r1 */
-       sparc_mov_reg_reg (code, sparc_g1, sparc_o0);
+       /* We receive the method address in %r1, so save it here */
+       sparc_st_imm (code, sparc_g1, sparc_sp, 128);
+
+       /* Save lmf since compilation can raise exceptions */
+       lmf_offset = - sizeof (MonoLMF);
+
+       /* Save the data for the parent (managed) frame */
+
+       /* Save ip */
+       sparc_st_imm (code, sparc_i7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ip));
+       /* Save sp */
+       sparc_st_imm (code, sparc_fp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, sp));
+       /* Save fp */
+       /* Load previous fp from the saved register window */
+       sparc_flushw (code);
+       sparc_ld_imm (code, sparc_fp, (sparc_i6 - 16) * 4, sparc_o7);
+       sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp));
+       /* Save method */
+       sparc_st_imm (code, sparc_g1, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method));
+
+       sparc_call_simple (code, (guint8*)mono_get_lmf_addr - (guint8*)code);
+       sparc_nop (code);
+
+       code = mono_sparc_emit_save_lmf (code, lmf_offset);
 
        if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
                tramp_addr = &sparc_class_init_trampoline;
        else
                tramp_addr = &sparc_magic_trampoline;
+       sparc_ld_imm (code, sparc_sp, 128, sparc_o0);
+       /* pass parent frame address as third argument */
+       sparc_mov_reg_reg (code, sparc_fp, sparc_o2);
        sparc_call_simple (code, tramp_addr - code);
        /* set %o1 to caller address in delay slot */
        sparc_mov_reg_reg (code, sparc_i7, sparc_o1);
 
+       /* Save result */
+       sparc_st_imm (code, sparc_o0, sparc_sp, 128);
+
+       /* Restore lmf */
+       code = mono_sparc_emit_restore_lmf (code, lmf_offset);
+
+       /* Reload result */
+       sparc_ld_imm (code, sparc_sp, 128, sparc_o0);
+
        if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
                sparc_ret (code);
        else
@@ -169,7 +214,7 @@ create_trampoline_code (MonoTrampolineType tramp_type)
                break;
        }
 
-       /* FIXME: flush icache */
+       mono_arch_flush_icache (buf, code - buf);
 
        return buf;
 }
@@ -208,7 +253,7 @@ create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type)
 MonoJitInfo*
 mono_arch_create_jump_trampoline (MonoMethod *method)
 {
-       MonoJitInfo *ji = create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC);
+       MonoJitInfo *ji = create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP);
 
        ji->method = method;
        return ji;