Mon Oct 15 10:37:15 CEST 2007 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / tramp-s390.c
index fe465ef6a9e097d064473d630aa9aa94a5b3ed9d..59f1403513262bce43ba8739c3cfce5bfebe7f76 100644 (file)
 
 #define GR_SAVE_SIZE           4*sizeof(long)
 #define FP_SAVE_SIZE           16*sizeof(double)
-#define CREATE_STACK_SIZE      (S390_MINIMAL_STACK_SIZE+GR_SAVE_SIZE+FP_SAVE_SIZE+2*sizeof(long))
-#define CREATE_GR_OFFSET       S390_MINIMAL_STACK_SIZE
+#define METHOD_SAVE_OFFSET     S390_MINIMAL_STACK_SIZE
+#define CREATE_GR_OFFSET       METHOD_SAVE_OFFSET+sizeof(gpointer)
 #define CREATE_FP_OFFSET       CREATE_GR_OFFSET+GR_SAVE_SIZE
 #define CREATE_LMF_OFFSET      CREATE_FP_OFFSET+FP_SAVE_SIZE
-#define METHOD_SAVE_OFFSET     S390_RET_ADDR_OFFSET-4
-
-/*------------------------------------------------------------------*/
-/* adapt to mini later...                                          */
-/*------------------------------------------------------------------*/
-#define mono_jit_share_code    (1)
+#define CREATE_STACK_SIZE      (CREATE_LMF_OFFSET+2*sizeof(long)+sizeof(MonoLMF))
 
 /*------------------------------------------------------------------*/
 /* Method-specific trampoline code fragment sizes                  */
@@ -53,7 +48,6 @@
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/arch/s390/s390-codegen.h>
-#include <mono/metadata/mono-debug-debugger.h>
 
 #include "mini.h"
 #include "mini-s390.h"
 /*                 T y p e d e f s                                  */
 /*------------------------------------------------------------------*/
 
-typedef enum {
-       MONO_TRAMPOLINE_GENERIC,
-       MONO_TRAMPOLINE_JUMP,
-       MONO_TRAMPOLINE_CLASS_INIT
-} MonoTrampolineType;
-
 /*========================= End of Typedefs ========================*/
 
 /*------------------------------------------------------------------*/
 /*                   P r o t o t y p e s                            */
 /*------------------------------------------------------------------*/
 
-/*------------------------------------------------------------------*/
-/* Address of the generic trampoline code.  This is used by the     */
-/* debugger to check whether a method is a trampoline.             */
-/*------------------------------------------------------------------*/
-guint8 *mono_generic_trampoline_code = NULL;
-
 /*========================= End of Prototypes ======================*/
 
 /*------------------------------------------------------------------*/
@@ -113,24 +95,20 @@ get_unbox_trampoline (MonoMethod *method, gpointer addr)
        int this_pos = s390_r2;
 
        start = addr;
-       if ((method->klass->valuetype)) {
-//     if ((method->klass->valuetype) && 
-//         (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
-               if ((!method->signature->ret->byref) && 
-                   (MONO_TYPE_ISSTRUCT (method->signature->ret)))
-                       this_pos = s390_r3;
-           
-               start = code = g_malloc (28);
-
-               s390_basr (code, s390_r13, 0);
-               s390_j    (code, 4);
-               s390_word (code, addr);
-               s390_l    (code, s390_r1, 0, s390_r13, 4);
-               s390_ahi  (code, this_pos, sizeof(MonoObject));
-               s390_br   (code, s390_r1);
-
-               g_assert ((code - start) <= 28);
-       }
+       if ((!mono_method_signature (method)->ret->byref) && 
+           (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)))
+               this_pos = s390_r3;
+    
+       start = code = mono_global_codeman_reserve (28);
+
+       s390_basr (code, s390_r13, 0);
+       s390_j    (code, 4);
+       s390_word (code, addr);
+       s390_l    (code, s390_r1, 0, s390_r13, 4);
+       s390_ahi  (code, this_pos, sizeof(MonoObject));
+       s390_br   (code, s390_r1);
+
+       g_assert ((code - start) <= 28);
 
        return start;
 }
@@ -166,9 +144,11 @@ s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
 {
        gpointer addr;
        gint32 displace;
-       int reg, base;
+       int reg;
+       guchar* base;
        unsigned short opcode;
-       char *fname;
+       MonoJitInfo *codeJi, 
+                   *addrJi;
 
        addr = mono_compile_method(method);
        g_assert(addr);
@@ -177,36 +157,48 @@ s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
        if (code) {
 
                /* The top bit needs to be ignored on S/390 */
-               (guint32) code &= 0x7fffffff;
+               code = (guchar*)((guint32)code & 0x7fffffff);
 
-               fname = mono_method_full_name (method, TRUE);
+               codeJi = mono_jit_info_table_find (mono_domain_get(), code);
+               addrJi = mono_jit_info_table_find (mono_domain_get(), addr);
+               if (mono_method_same_domain (codeJi, addrJi)) {
 
-               opcode = *((unsigned short *) (code - 6));
-               switch (opcode) {
+                       opcode = *((unsigned short *) (code - 6));
+                       switch (opcode) {
                        case 0x5810 :
                                /* This is a bras r14,r1 instruction */
                                code    -= 4;
                                reg      = *code >> 4;
                                displace = *((short *)code) & 0x0fff;
                                if (reg > 5) 
-                                       base = *((int *) (sp + S390_REG_SAVE_OFFSET+
+                                       base = *((guchar **) (sp + S390_REG_SAVE_OFFSET+
                                                               sizeof(int)*(reg-6)));
                                else
-                                       base = *((int *) (sp + CREATE_GR_OFFSET+
+                                       base = *((guchar **) ((sp - CREATE_STACK_SIZE) + 
+                                                              CREATE_GR_OFFSET +
                                                               sizeof(int)*(reg-2)));
-                               addr = get_unbox_trampoline(method, addr);
+
+                               if ((method->klass->valuetype) && 
+                                   (!mono_aot_is_got_entry(code, base))) 
+                                       addr = get_unbox_trampoline(method, addr);
+
                                code = base + displace;
-                               s390_patch(code, addr);
+                               if (mono_domain_owns_vtable_slot(mono_domain_get(), 
+                                                                code))
+                                       s390_patch(code, (guint32) addr);
                                break;
                        case 0xc0e5 :
                                /* This is the 'brasl' instruction */
                                code    -= 4;
                                displace = ((gint32) addr - (gint32) (code - 2)) / 2;
-                               s390_patch (code, displace);
-                               mono_arch_flush_icache (code, 4);
+                               if (mono_method_same_domain (codeJi, addrJi)) {
+                                       s390_patch (code, displace);
+                                       mono_arch_flush_icache (code, 4);
+                               }
                                break;
                        default :
                                g_error("Unable to patch instruction prior to %p",code);
+                       }
                }
        }
 
@@ -241,42 +233,25 @@ s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - create_trampoline_code                            */
+/* Name                - mono_arch_create_trampoline_code                            */
 /*                                                                  */
 /* Function    - Create the designated type of trampoline according*/
 /*                to the 'tramp_type' parameter.                    */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
-static guchar*
-create_trampoline_code (MonoTrampolineType tramp_type)
+guchar*
+mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
 {
 
        guint8 *buf, *code = NULL;
-       static guint8* generic_jump_trampoline = NULL;
-       static guint8 *generic_class_init_trampoline = NULL;
-       int i, offset;
-
-       switch (tramp_type) {
-       case MONO_TRAMPOLINE_GENERIC:
-               if (mono_generic_trampoline_code)
-                       return mono_generic_trampoline_code;
-               break;
-       case MONO_TRAMPOLINE_JUMP:
-               if (generic_jump_trampoline)
-                       return generic_jump_trampoline;
-               break;
-       case MONO_TRAMPOLINE_CLASS_INIT:
-               if (generic_class_init_trampoline)
-                       return generic_class_init_trampoline;
-               break;
-       }
+       int i, offset, lmfOffset;
 
        if(!code) {
                /* Now we'll create in 'buf' the S/390 trampoline code. This
                 is the trampoline code common to all methods  */
                
-               code = buf = g_malloc(512);
+               code = buf = mono_global_codeman_reserve(512);
                
                /*-----------------------------------------------------------
                STEP 0: First create a non-standard function prologue with a
@@ -287,6 +262,7 @@ create_trampoline_code (MonoTrampolineType tramp_type)
                s390_lr   (buf, s390_r11, s390_r15);
                s390_ahi  (buf, STK_BASE, -CREATE_STACK_SIZE);
                s390_st   (buf, s390_r11, 0, STK_BASE, 0);
+               s390_st   (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
                s390_stm  (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
 
                /* Save the FP registers */
@@ -309,19 +285,82 @@ create_trampoline_code (MonoTrampolineType tramp_type)
                s390_l    (buf, s390_r1, 0, s390_r13, 4);
                s390_basr (buf, s390_r14, s390_r1);
 
-               /* XXX Update LMF !!! */
-               
-               /*----------------------------------------------------------
-               STEP 2: call 's390_magic_trampoline()', who will compile the
-               code and fix the method vtable entry for us
-               ----------------------------------------------------------*/
+               /*---------------------------------------------------------------*/
+               /* we build the MonoLMF structure on the stack - see mini-s390.h */
+               /* Keep in sync with the code in mono_arch_emit_prolog           */
+               /*---------------------------------------------------------------*/
+               lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
+                                                                                       
+               s390_lr    (buf, s390_r13, STK_BASE);
+               s390_ahi   (buf, s390_r13, lmfOffset);  
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Set lmf.lmf_addr = jit_tls->lmf                               */     
+               /*---------------------------------------------------------------*/     
+               s390_st    (buf, s390_r2, 0, s390_r13,                          
+                           G_STRUCT_OFFSET(MonoLMF, lmf_addr));                        
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Get current lmf                                               */     
+               /*---------------------------------------------------------------*/     
+               s390_l     (buf, s390_r0, 0, s390_r2, 0);                               
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Set our lmf as the current lmf                                */     
+               /*---------------------------------------------------------------*/     
+               s390_st    (buf, s390_r13, 0, s390_r2, 0);                              
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Have our lmf.previous_lmf point to the last lmf               */     
+               /*---------------------------------------------------------------*/     
+               s390_st    (buf, s390_r0, 0, s390_r13,                          
+                           G_STRUCT_OFFSET(MonoLMF, previous_lmf));                    
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* save method info                                              */     
+               /*---------------------------------------------------------------*/     
+               s390_l     (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
+               s390_st    (buf, s390_r1, 0, s390_r13,                          
+                           G_STRUCT_OFFSET(MonoLMF, method));                          
+                                                                       
+               /*---------------------------------------------------------------*/     
+               /* save the current SP                                           */     
+               /*---------------------------------------------------------------*/     
+               s390_l     (buf, s390_r1, 0, STK_BASE, 0);
+               s390_st    (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));  
+                                                                       
+               /*---------------------------------------------------------------*/     
+               /* save the current IP                                           */     
+               /*---------------------------------------------------------------*/     
+               if (tramp_type == MONO_TRAMPOLINE_JUMP) {
+                       s390_lhi   (buf, s390_r1, 0);
+               } else {
+                       s390_l     (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
+                       s390_la    (buf, s390_r1, 0, s390_r1, 0);
+               }
+               s390_st    (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));  
+                                                                                       
+               /*---------------------------------------------------------------*/     
+               /* Save general and floating point registers                     */     
+               /*---------------------------------------------------------------*/     
+               s390_stm   (buf, s390_r2, s390_r12, s390_r13,                           
+                           G_STRUCT_OFFSET(MonoLMF, gregs[2]));                        
+               for (i = 0; i < 16; i++) {                                              
+                       s390_std  (buf, i, 0, s390_r13,                                 
+                                  G_STRUCT_OFFSET(MonoLMF, fregs[i]));                 
+               }                                                                       
+
+               /*---------------------------------------------------------------*/
+               /* STEP 2: call 's390_magic_trampoline()', who will compile the  */
+               /* code and fix the method vtable entry for us                   */
+               /*---------------------------------------------------------------*/
                                
                /* Set arguments */
                
-               /* Arg 1: MonoMethod *method. It was put in r11 by the
+               /* Arg 1: MonoMethod *method. It was put in r1 by the
                method-specific trampoline code, and then saved before the call
-               to mono_get_lmf_addr()'. Restore r13, by the way :-) */
-               s390_l  (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
+               to mono_get_lmf_addr()'. */
+               s390_l  (buf, s390_r2, 0, STK_BASE, METHOD_SAVE_OFFSET);
                
                /* Arg 2: code (next address to the instruction that called us) */
                if (tramp_type == MONO_TRAMPOLINE_JUMP) {
@@ -332,6 +371,7 @@ create_trampoline_code (MonoTrampolineType tramp_type)
                
                /* Arg 3: stack pointer */
                s390_lr   (buf, s390_r4, STK_BASE);
+               s390_ahi  (buf, s390_r4, CREATE_STACK_SIZE);
                
                /* Calculate call address and call
                's390_magic_trampoline'. Return value will be in r2 */
@@ -348,14 +388,12 @@ create_trampoline_code (MonoTrampolineType tramp_type)
                /* OK, code address is now on r2. Move it to r1, so that we
                can restore r2 and use it from r1 later */
                s390_lr   (buf, s390_r1, s390_r2);
-               
 
                /*----------------------------------------------------------
                STEP 3: Restore the LMF
                ----------------------------------------------------------*/
-               
-               /* XXX Do it !!! */
-               
+               restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
+       
                /*----------------------------------------------------------
                STEP 4: call the compiled method
                ----------------------------------------------------------*/
@@ -384,18 +422,6 @@ create_trampoline_code (MonoTrampolineType tramp_type)
                g_assert ((buf - code) <= 512);
        }
 
-       switch (tramp_type) {
-       case MONO_TRAMPOLINE_GENERIC:
-               mono_generic_trampoline_code = code;
-               break;
-       case MONO_TRAMPOLINE_JUMP:
-               generic_jump_trampoline = code;
-               break;
-       case MONO_TRAMPOLINE_CLASS_INIT:
-               generic_class_init_trampoline = code;
-               break;
-       }
-
        return code;
 }
 
@@ -418,16 +444,16 @@ mono_arch_create_jump_trampoline (MonoMethod *method)
        MonoDomain *domain = mono_domain_get();
        gint32 displace;
 
-       tramp = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
+       tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
 
        mono_domain_lock (domain);
        code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
        mono_domain_unlock (domain);
 
-       s390_basr (buf, s390_r13, 0);
+       s390_basr (buf, s390_r1, 0);
        s390_j    (buf, 4);
        s390_word (buf, method);
-       s390_l    (buf, s390_r13, 0, s390_r13, 4);
+       s390_l    (buf, s390_r1, 0, s390_r1, 4);
        displace = (tramp - buf) / 2;
        s390_jcl  (buf, S390_CC_UN, displace);
 
@@ -482,19 +508,19 @@ mono_arch_create_jit_trampoline (MonoMethod *method)
        static guint8 *vc = NULL;
        gint32 displace;
 
-       vc = create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
+       vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC);
 
-       /* This is the method-specific part of the trampoline. Its purpose is
-       to provide the generic part with the MonoMethod *method pointer. We'll
-       use r13 to keep that value, for instance. However, the generic part of
-       the trampoline relies on r11 having the same value it had before coming
-       here, so we must save it before. */
-       code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
+       /*----------------------------------------------------------*/
+       /* This is the method-specific part of the trampoline. Its  */
+       /* purpose is to provide the generic part with the          */
+       /* MonoMethod *method pointer. We'll use r1 to keep it.     */
+       /*----------------------------------------------------------*/
+       code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
 
-       s390_basr (buf, s390_r13, 0);
+       s390_basr (buf, s390_r1, 0);
        s390_j    (buf, 4);
        s390_word (buf, method);
-       s390_l    (buf, s390_r13, 0, s390_r13, 4);
+       s390_l    (buf, s390_r1, 0, s390_r1, 4);
        displace = (vc - buf) / 2;
        s390_jcl  (buf, S390_CC_UN, displace);
 
@@ -504,8 +530,6 @@ mono_arch_create_jit_trampoline (MonoMethod *method)
        /* Sanity check */
        g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
        
-       mono_jit_stats.method_trampolines++;
-
        return code;
 }
 
@@ -532,14 +556,17 @@ mono_arch_create_class_init_trampoline (MonoVTable *vtable)
 {
        guint8 *code, *buf, *tramp;
 
-       tramp = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
+       tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
 
-       /* This is the method-specific part of the trampoline. Its purpose is
-       to provide the generic part with the MonoMethod *method pointer. We'll
-       use r11 to keep that value, for instance. However, the generic part of
-       the trampoline relies on r11 having the same value it had before coming
-       here, so we must save it before. */
-       code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
+       /*-----------------------------------------------------------*/
+       /* This is the method-specific part of the trampoline. Its   */
+       /* purpose is to provide the generic part with the MonoMethod*/
+       /* *method pointer. We'll use r11 to keep that value, for    */
+       /* instance. However, the generic part of the trampoline     */
+       /* relies on r11 having the same value it had before coming  */
+       /* here, so we must save it before.                          */
+       /*-----------------------------------------------------------*/
+       code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
 
        s390_st   (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
        s390_ahi  (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
@@ -582,14 +609,12 @@ mono_arch_create_class_init_trampoline (MonoVTable *vtable)
 /*------------------------------------------------------------------*/
 
 gpointer
-mono_debugger_create_notification_function (gpointer *notification_address)
+mono_debugger_create_notification_function (void)
 {
        guint8 *ptr, *buf;
 
-       ptr = buf = g_malloc0 (16);
+       ptr = buf = mono_global_codeman_reserve (16);
        s390_break (buf);
-       if (notification_address)
-               *notification_address = buf;
        s390_br (buf, s390_r14);
 
        return ptr;