2009-05-26 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mono / mini / tramp-ppc.c
index 2b80b8b38f101da635ccd219310ecca1db4eadc1..3c36a33cd5aa4889c726d6c6000a57b49007c0b9 100644 (file)
@@ -22,6 +22,8 @@
 #include "mini.h"
 #include "mini-ppc.h"
 
+static guint8* nullified_class_init_trampoline;
+
 /*
  * Return the instruction to jump from code to target, 0 if not
  * reachable with a single instruction
@@ -59,7 +61,7 @@ mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m,
        int this_pos = 3;
        guint32 short_branch;
        MonoDomain *domain = mono_domain_get ();
-       int size = MONO_PPC_32_64_CASE (20, 32);
+       int size = MONO_PPC_32_64_CASE (20, 32) + PPC_FTNPTR_SIZE;
 
        addr = mono_get_addr_from_ftnptr (addr);
 
@@ -67,10 +69,11 @@ mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m,
                this_pos = 4;
            
        mono_domain_lock (domain);
-       start = code = mono_code_manager_reserve (domain->code_mp, size);
+       start = code = mono_domain_code_reserve (domain, size);
+       code = mono_ppc_create_pre_code_ftnptr (code);
        short_branch = branch_for_target_reachable (code + 4, addr);
        if (short_branch)
-               mono_code_manager_commit (domain->code_mp, code, size, 8);
+               mono_domain_code_commit (domain, code, size, 8);
        mono_domain_unlock (domain);
 
        if (short_branch) {
@@ -87,7 +90,45 @@ mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m,
        /*g_print ("unbox trampoline at %d for %s:%s\n", this_pos, m->klass->name, m->name);
        g_print ("unbox code is at %p for method at %p\n", start, addr);*/
 
-       return mono_create_ftnptr (domain, start);
+       return start;
+}
+
+/*
+ * mono_arch_get_static_rgctx_trampoline:
+ *
+ *   Create a trampoline which sets RGCTX_REG to MRGCTX, then jumps to ADDR.
+ */
+gpointer
+mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
+{
+       guint8 *code, *start;
+       guint32 short_branch;
+       MonoDomain *domain = mono_domain_get ();
+       int size = MONO_PPC_32_64_CASE (24, 36) + PPC_FTNPTR_SIZE;
+
+       addr = mono_get_addr_from_ftnptr (addr);
+
+       mono_domain_lock (domain);
+       start = code = mono_domain_code_reserve (domain, size);
+       code = mono_ppc_create_pre_code_ftnptr (code);
+       short_branch = branch_for_target_reachable (code + 8, addr);
+       if (short_branch)
+               mono_domain_code_commit (domain, code, size, 12);
+       mono_domain_unlock (domain);
+
+       if (short_branch) {
+               ppc_load (code, MONO_ARCH_RGCTX_REG, mrgctx);
+               ppc_emit32 (code, short_branch);
+       } else {
+               ppc_load (code, ppc_r0, addr);
+               ppc_mtctr (code, ppc_r0);
+               ppc_load (code, MONO_ARCH_RGCTX_REG, mrgctx);
+               ppc_bcctr (code, 20, 0);
+       }
+       mono_arch_flush_icache (start, code - start);
+       g_assert ((code - start) <= size);
+
+       return start;
 }
 
 void
@@ -125,7 +166,7 @@ mono_arch_patch_plt_entry (guint8 *code, guint8 *addr)
 void
 mono_arch_nullify_class_init_trampoline (guint8 *code, gssize *regs)
 {
-       return;
+       mono_arch_patch_callsite (NULL, code, nullified_class_init_trampoline);
 }
 
 void
@@ -173,7 +214,7 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
        guint8 *buf, *code = NULL;
        int i, offset;
        gconstpointer tramp_handler;
-       int size = MONO_PPC_32_64_CASE (512, 688);
+       int size = MONO_PPC_32_64_CASE (516, 692);
 
        /* Now we'll create in 'buf' the PowerPC trampoline code. This
           is the trampoline code common to all methods  */
@@ -192,7 +233,7 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
         * now the integer registers.
         */
        offset = STACK - sizeof (MonoLMF) + G_STRUCT_OFFSET (MonoLMF, iregs);
-       ppc_store_multiple_regs (buf, ppc_r13, ppc_r1, offset);
+       ppc_store_multiple_regs (buf, ppc_r13, offset, ppc_r1);
 
        /* Now save the rest of the registers below the MonoLMF struct, first 14
         * fp regs and then the 13 gregs.
@@ -240,7 +281,9 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
                ppc_load_reg (buf, ppc_r5, GREGS_OFFSET, ppc_r1);
        if ((tramp_type == MONO_TRAMPOLINE_JIT) || (tramp_type == MONO_TRAMPOLINE_JUMP))
                ppc_store_reg (buf, ppc_r5, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
-       ppc_store_reg (buf, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
+       /* store the frame pointer of the calling method */
+       ppc_addi (buf, ppc_r0, ppc_sp, STACK);
+       ppc_store_reg (buf, ppc_r0, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
        /* save the IP (caller ip) */
        if (tramp_type == MONO_TRAMPOLINE_JUMP) {
                ppc_li (buf, ppc_r0, 0);
@@ -276,8 +319,7 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
         */
        if (!MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
-               if (tramp_type != MONO_TRAMPOLINE_DELEGATE)
-                       ppc_load_reg (buf, ppc_r3, 0, ppc_r3);
+               ppc_load_reg (buf, ppc_r3, 0, ppc_r3);
 #endif
                ppc_mtctr (buf, ppc_r3);
        }
@@ -296,7 +338,7 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
        /* *(lmf_addr) = previous_lmf */
        ppc_store_reg (buf, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
        /* restore iregs */
-       ppc_load_multiple_regs (buf, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
+       ppc_load_multiple_regs (buf, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
        /* restore fregs */
        for (i = 14; i < 32; i++)
                ppc_lfd (buf, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
@@ -334,6 +376,13 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
        /* Sanity check */
        g_assert ((buf - code) <= size);
 
+       if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
+               guint32 code_len;
+
+               /* Initialize the nullified class init trampoline used in the AOT case */
+               nullified_class_init_trampoline = mono_arch_get_nullified_class_init_trampoline (&code_len);
+       }
+
        return code;
 }
 
@@ -347,13 +396,13 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty
        tramp = mono_get_trampoline_code (tramp_type);
 
        mono_domain_lock (domain);
-       code = buf = mono_code_manager_reserve_align (domain->code_mp, TRAMPOLINE_SIZE, 4);
+       code = buf = mono_domain_code_reserve_align (domain, TRAMPOLINE_SIZE, 4);
        short_branch = branch_for_target_reachable (code + MONO_PPC_32_64_CASE (8, 5*4), tramp);
 #ifdef __mono_ppc64__
        /* FIXME: make shorter if possible */
 #else
        if (short_branch)
-               mono_code_manager_commit (domain->code_mp, code, TRAMPOLINE_SIZE, 12);
+               mono_domain_code_commit (domain, code, TRAMPOLINE_SIZE, 12);
 #endif
        mono_domain_unlock (domain);
 
@@ -504,7 +553,7 @@ mono_arch_create_generic_class_init_trampoline (void)
        guint8 *jump;
        int tramp_size;
 
-       tramp_size = 32;
+       tramp_size = MONO_PPC_32_64_CASE (32, 44);
 
        code = buf = mono_global_codeman_reserve (tramp_size);
 
@@ -532,3 +581,22 @@ mono_arch_create_generic_class_init_trampoline (void)
 
        return buf;
 }
+
+gpointer
+mono_arch_get_nullified_class_init_trampoline (guint32 *code_len)
+{
+       guint8 *code, *buf;
+       guint32 tramp_size = 64;
+
+       code = buf = mono_global_codeman_reserve (tramp_size);
+       code = mono_ppc_create_pre_code_ftnptr (code);
+       ppc_blr (code);
+
+       mono_arch_flush_icache (buf, code - buf);
+
+       *code_len = code - buf;
+
+       g_assert (code - buf <= tramp_size);
+
+       return buf;
+}