2005-12-11 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / tramp-s390.c
index 51d5781bd74607b8d57e0d16c4b1e15e84e285c7..47453ea4413a0a099689e00b2fd120a8de97cb1b 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 CREATE_FP_OFFSET       CREATE_GR_OFFSET+GR_SAVE_SIZE
 #define CREATE_LMF_OFFSET      CREATE_FP_OFFSET+FP_SAVE_SIZE
+#define CREATE_STACK_SIZE      (CREATE_LMF_OFFSET+2*sizeof(long)+sizeof(MonoLMF))
 #define METHOD_SAVE_OFFSET     S390_RET_ADDR_OFFSET-4
 
-/*------------------------------------------------------------------*/
-/* adapt to mini later...                                          */
-/*------------------------------------------------------------------*/
-#define mono_jit_share_code    (1)
-
 /*------------------------------------------------------------------*/
 /* Method-specific trampoline code fragment sizes                  */
 /*------------------------------------------------------------------*/
 /*                 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 +96,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 +145,12 @@ 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 +159,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;
-
-               fname = mono_method_full_name (method, TRUE);
-
-               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+
-                                                              sizeof(int)*(reg-6)));
-                               else
-                                       base = *((int *) (sp + CREATE_GR_OFFSET+
-                                                              sizeof(int)*(reg-2)));
-                               addr = get_unbox_trampoline(method, addr);
-                               code = base + displace;
-                               s390_patch(code, 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);
-                               break;
-                       default :
-                               g_error("Unable to patch instruction prior to %p",code);
+               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) {
+                               case 0x5810 :
+                                       /* This is a bras r14,r1 instruction */
+                                       code    -= 4;
+                                       reg      = *code >> 4;
+                                       displace = *((short *)code) & 0x0fff;
+                                       if (reg > 5) 
+                                               base = *((guchar **) (sp + S390_REG_SAVE_OFFSET+
+                                                                      sizeof(int)*(reg-6)));
+                                       else
+                                               base = *((guchar **) (sp + CREATE_GR_OFFSET+
+                                                                      sizeof(int)*(reg-2)));
+
+                                       if ((method->klass->valuetype) && 
+                                           (!mono_aot_is_got_entry(code, base))) 
+                                               addr = get_unbox_trampoline(method, addr);
+
+                                       code = base + displace;
+                                       if (mono_domain_owns_vtable_slot(mono_domain_get(), 
+                                                                        code))
+                                               s390_patch(code, addr);
+                                       break;
+                               case 0xc0e5 :
+                                       /* This is the 'brasl' instruction */
+                                       code    -= 4;
+                                       displace = ((gint32) addr - (gint32) (code - 2)) / 2;
+                                       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 +235,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
@@ -309,12 +286,75 @@ 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, s390_r11, 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 */
                
@@ -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,7 +444,7 @@ 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);
@@ -482,21 +508,14 @@ mono_arch_create_jit_trampoline (MonoMethod *method)
        static guint8 *vc = NULL;
        gint32 displace;
 
-       /* previously created trampoline code */
-       if (method->info)
-               return method->info;
-
-       if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
-               return mono_arch_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
-
-       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);
+       code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
 
        s390_basr (buf, s390_r13, 0);
        s390_j    (buf, 4);
@@ -511,11 +530,6 @@ mono_arch_create_jit_trampoline (MonoMethod *method)
        /* Sanity check */
        g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
        
-       /* Store trampoline address */
-       method->info = code;
-
-       mono_jit_stats.method_trampolines++;
-
        return code;
 }
 
@@ -542,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);
@@ -596,7 +613,7 @@ mono_debugger_create_notification_function (gpointer *notification_address)
 {
        guint8 *ptr, *buf;
 
-       ptr = buf = g_malloc0 (16);
+       ptr = buf = mono_global_codeman_reserve (16);
        s390_break (buf);
        if (notification_address)
                *notification_address = buf;
@@ -604,3 +621,5 @@ mono_debugger_create_notification_function (gpointer *notification_address)
 
        return ptr;
 }
+
+/*========================= End of Function ========================*/