*** empty log message ***
[mono.git] / mono / jit / emit-x86.c
index 8acf7b19cb3443746a6982259be6bbb416a85dc7..90930f55b6bc949b8e5ad524c82dd04a6015c984 100644 (file)
@@ -66,6 +66,9 @@ int mono_x86_have_cmov = 0;
 static int 
 cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
 {
+#ifdef PIC
+       return 0;
+#else
        int have_cpuid = 0;
        __asm__  __volatile__ (
                "pushfl\n"
@@ -91,6 +94,7 @@ cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
                return 1;
        }
        return 0;
+#endif
 }
 
 void
@@ -105,40 +109,101 @@ mono_cpu_detect (void) {
        }
 }
 
+/*
+ * arch_get_argument_info:
+ * @csig:  a method signature
+ * @param_count: the number of parameters to consider
+ * @arg_info: an array to store the result infos
+ *
+ * Gathers information on parameters such as size, alignment and
+ * padding. arg_info should be large enought to hold param_count + 1 entries. 
+ *
+ * Returns the size of the activation frame.
+ */
+int
+arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
+{
+       int k, frame_size = 0;
+       int size, align, pad;
+       int offset = 8;
+
+       if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
+               frame_size += sizeof (gpointer);
+               offset += 4;
+       }
+
+       arg_info [0].offset = offset;
+
+       if (csig->hasthis) {
+               frame_size += sizeof (gpointer);
+               offset += 4;
+       }
+
+       arg_info [0].size = frame_size;
+
+       for (k = 0; k < param_count; k++) {
+               
+               if (csig->pinvoke)
+                       size = mono_type_native_stack_size (csig->params [k], &align);
+               else
+                       size = mono_type_stack_size (csig->params [k], &align);
+               
+               frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
+               arg_info [k].pad = pad;
+               frame_size += size;
+               arg_info [k + 1].pad = 0;
+               arg_info [k + 1].size = size;
+               offset += pad;
+               arg_info [k + 1].offset = offset;
+               offset += size;
+       }
+
+       align = MONO_FRAME_ALIGNMENT;
+       frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
+       arg_info [k].pad = pad;
+
+       return frame_size;
+}
+
 static void
 enter_method (MonoMethod *method, char *ebp)
 {
        int i, j;
        MonoClass *class;
        MonoObject *o;
+       MonoJitArgumentInfo *arg_info;
+       MonoMethodSignature *sig;
        char *fname;
 
        fname = mono_method_full_name (method, TRUE);
        printf ("ENTER: %s\n(", fname);
        g_free (fname);
        
-       if (((int)ebp & 3) != 0) {
+       if (((int)ebp & (MONO_FRAME_ALIGNMENT - 1)) != 0) {
                g_error ("unaligned stack detected (%p)", ebp);
        }
 
-       ebp += 8;
+       sig = method->signature;
 
-       if (ISSTRUCT (method->signature->ret)) {
-               int size, align;
-               
-               g_assert (!method->signature->ret->byref);
+       if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
+               g_assert (!sig->pinvoke);
+
+       arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
 
-               size = mono_type_stack_size (method->signature->ret, &align);
+       arch_get_argument_info (sig, sig->param_count, arg_info);
 
-               printf ("VALUERET:%p, ", *((gpointer *)ebp));
-               ebp += sizeof (gpointer);
+       if (MONO_TYPE_ISSTRUCT (method->signature->ret)) {
+               g_assert (!method->signature->ret->byref);
+
+               printf ("VALUERET:%p, ", *((gpointer *)(ebp + 8)));
        }
 
        if (method->signature->hasthis) {
+               gpointer *this = (gpointer *)(ebp + arg_info [0].offset);
                if (method->klass->valuetype) {
-                       printf ("value:%p, ", *((gpointer *)ebp));
+                       printf ("value:%p, ", *this);
                } else {
-                       o = *((MonoObject **)ebp);
+                       o = *((MonoObject **)this);
 
                        if (o) {
                                class = o->vtable->klass;
@@ -151,16 +216,16 @@ enter_method (MonoMethod *method, char *ebp)
                        } else 
                                printf ("this:NULL, ");
                }
-               ebp += sizeof (gpointer);
        }
 
        for (i = 0; i < method->signature->param_count; ++i) {
-               MonoType *type = method->signature->params [i];
-               int size, align;
-               size = mono_type_stack_size (type, &align);
+               gpointer *cpos = (gpointer *)(ebp + arg_info [i + 1].offset);
+               int size = arg_info [i + 1].size;
 
+               MonoType *type = method->signature->params [i];
+               
                if (type->byref) {
-                       printf ("[BYREF:%p], ", *((gpointer *)ebp)); 
+                       printf ("[BYREF:%p], ", *cpos); 
                } else switch (type->type) {
                        
                case MONO_TYPE_BOOLEAN:
@@ -173,10 +238,10 @@ enter_method (MonoMethod *method, char *ebp)
                case MONO_TYPE_U4:
                case MONO_TYPE_I:
                case MONO_TYPE_U:
-                       printf ("%d, ", *((int *)(ebp)));
+                       printf ("%d, ", *((int *)(cpos)));
                        break;
                case MONO_TYPE_STRING: {
-                       MonoString *s = *((MonoString **)ebp);
+                       MonoString *s = *((MonoString **)cpos);
                        if (s) {
                                g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
                                printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
@@ -186,7 +251,7 @@ enter_method (MonoMethod *method, char *ebp)
                }
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT: {
-                       o = *((MonoObject **)ebp);
+                       o = *((MonoObject **)cpos);
                        if (o) {
                                class = o->vtable->klass;
                    
@@ -197,7 +262,7 @@ enter_method (MonoMethod *method, char *ebp)
                                } else
                                        printf ("[%s.%s:%p], ", class->name_space, class->name, o);
                        } else {
-                               printf ("%p, ", *((gpointer *)(ebp)));                          
+                               printf ("%p, ", *((gpointer *)(cpos)));                         
                        }
                        break;
                }
@@ -205,30 +270,26 @@ enter_method (MonoMethod *method, char *ebp)
                case MONO_TYPE_FNPTR:
                case MONO_TYPE_ARRAY:
                case MONO_TYPE_SZARRAY:
-                       printf ("%p, ", *((gpointer *)(ebp)));
+                       printf ("%p, ", *((gpointer *)(cpos)));
                        break;
                case MONO_TYPE_I8:
-                       printf ("%lld, ", *((gint64 *)(ebp)));
+                       printf ("%lld, ", *((gint64 *)(cpos)));
                        break;
                case MONO_TYPE_R4:
-                       printf ("%f, ", *((float *)(ebp)));
+                       printf ("%f, ", *((float *)(cpos)));
                        break;
                case MONO_TYPE_R8:
-                       printf ("%f, ", *((double *)(ebp)));
+                       printf ("%f, ", *((double *)(cpos)));
                        break;
                case MONO_TYPE_VALUETYPE: 
                        printf ("[");
                        for (j = 0; j < size; j++)
-                               printf ("%02x,", *((guint8*)ebp +j));
+                               printf ("%02x,", *((guint8*)cpos +j));
                        printf ("], ");
                        break;
                default:
                        printf ("XX, ");
                }
-
-               g_assert (align == 4 || align == 8);
-               ebp += size + align - 1;
-               ebp = (gpointer)((unsigned)ebp & ~(align - 1));
        }
 
        printf (")\n");
@@ -350,28 +411,40 @@ arch_emit_prologue (MonoFlowGraph *cfg)
                x86_push_imm (cfg->code, method);
        
                /* get the address of lmf for the current thread */
-               x86_call_code (cfg->code, mono_get_lmf_addr);
+               mono_add_jump_info (cfg, cfg->code, MONO_JUMP_INFO_ABS, mono_get_lmf_addr);
+               x86_call_code (cfg->code, 0);
+
                /* push lmf */
                x86_push_reg (cfg->code, X86_EAX); 
                /* push *lfm (previous_lmf) */
                x86_push_membase (cfg->code, X86_EAX, 0);
                /* *(lmf) = ESP */
                x86_mov_membase_reg (cfg->code, X86_EAX, 0, X86_ESP, 4);
-       }
+       } else {
+
+#if 0
+               /* activation frame alignment check */
+               x86_mov_reg_reg (cfg->code, X86_EAX, X86_ESP, 4);
+               x86_alu_reg_imm (cfg->code, X86_AND, X86_EAX, MONO_FRAME_ALIGNMENT - 1);
+               x86_alu_reg_imm (cfg->code, X86_CMP, X86_EAX, 0);
+               x86_branch32 (cfg->code, X86_CC_EQ, 1, FALSE);
+               x86_breakpoint (cfg->code);
+#endif
 
-       if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
-               x86_push_reg (cfg->code, X86_EBX);
-               pos += 4;
-       }
+               if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
+                       x86_push_reg (cfg->code, X86_EBX);
+                       pos += 4;
+               }
 
-       if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
-               x86_push_reg (cfg->code, X86_EDI);
-               pos += 4;
-       }
+               if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
+                       x86_push_reg (cfg->code, X86_EDI);
+                       pos += 4;
+               }
 
-       if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
-               x86_push_reg (cfg->code, X86_ESI);
-               pos += 4;
+               if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
+                       x86_push_reg (cfg->code, X86_ESI);
+                       pos += 4;
+               }
        }
 
        alloc_size -= pos;
@@ -533,29 +606,25 @@ arch_emit_epilogue (MonoFlowGraph *cfg)
                x86_pop_reg (cfg->code, X86_EAX);
        }
 
+       pos = 0;
+       
        if (cfg->method->save_lmf) {
-               pos = -sizeof (MonoLMF) - 4;
-       } else
-               pos = -4;
-
-       if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
-               x86_mov_reg_membase (cfg->code, X86_EBX, X86_EBP, pos, 4);
-               pos -= 4;
-       }
-       if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
-               x86_mov_reg_membase (cfg->code, X86_EDI, X86_EBP, pos, 4);
-               pos -= 4;
+               pos = -sizeof (MonoLMF);
+       } else {
+               if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
+                       pos -= 4;
        }
-       if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
-               x86_mov_reg_membase (cfg->code, X86_ESI, X86_EBP, pos, 4);
-               pos -= 4;
+               if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
+                       pos -= 4;
+               }
+               if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
+                       pos -= 4;
+               }
        }
-
-       if (cfg->method->save_lmf) {
-               pos = -sizeof (MonoLMF);
-
+       if (pos)
                x86_lea_membase (cfg->code, X86_ESP, X86_EBP, pos);
 
+       if (cfg->method->save_lmf) {
                /* ebx = previous_lmf */
                x86_pop_reg (cfg->code, X86_EBX);
                /* edi = lmf */
@@ -572,12 +641,50 @@ arch_emit_epilogue (MonoFlowGraph *cfg)
                x86_pop_reg (cfg->code, X86_EDI);
                x86_pop_reg (cfg->code, X86_EBX);
 
+       } else {
+
+               if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
+                       x86_pop_reg (cfg->code, X86_ESI);
+               }
+               if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
+                       x86_pop_reg (cfg->code, X86_EDI);
+               }
+               if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
+                       x86_pop_reg (cfg->code, X86_EBX);
+               }
        }
 
        x86_leave (cfg->code);
        x86_ret (cfg->code);
 }
 
+static void
+init_varinfo (MonoFlowGraph *cfg, MonoVarInfo *vi)
+{
+       vi->range.last_use.abs_pos = 0;
+       vi->range.first_use.pos.bid = 0xffff;
+       vi->range.first_use.pos.tid = 0;        
+       vi->isvolatile = 0;
+       vi->reg = -1;
+       vi->varnum = cfg->varinfo->len;
+}
+
+int
+arch_allocate_arg (MonoFlowGraph *cfg, MonoJitArgumentInfo *info, MonoValueType type)
+{
+       MonoVarInfo vi;
+
+       mono_jit_stats.allocate_var++;
+
+       init_varinfo (cfg, &vi);
+       vi.isvolatile = 1;
+       
+       SET_VARINFO (vi, type, MONO_ARGVAR, info->offset, info->size);
+       g_array_append_val (cfg->varinfo, vi);
+
+       return cfg->varinfo->len - 1;
+}
+
 int
 arch_allocate_var (MonoFlowGraph *cfg, int size, int align, MonoVarType vartype, MonoValueType type)
 {
@@ -585,43 +692,17 @@ arch_allocate_var (MonoFlowGraph *cfg, int size, int align, MonoVarType vartype,
 
        mono_jit_stats.allocate_var++;
 
-       vi.range.last_use.abs_pos = 0;
-       vi.range.first_use.pos.bid = 0xffff;
-       vi.range.first_use.pos.tid = 0; 
-       vi.isvolatile = 0;
-       vi.reg = -1;
-       vi.varnum = cfg->varinfo->len;
+       init_varinfo (cfg, &vi);
 
        if (size != sizeof (gpointer))
                vi.isvolatile = 1;
        
-       switch (vartype) {
-       case MONO_TEMPVAR:
-       case MONO_LOCALVAR: {
-               cfg->locals_size += size;
-               cfg->locals_size += align - 1;
-               cfg->locals_size &= ~(align - 1);
-
-               SET_VARINFO (vi, type, vartype, - cfg->locals_size, size);
-               g_array_append_val (cfg->varinfo, vi);
-               break;
-       }
-       case MONO_ARGVAR: {
-               int arg_start = 8 + cfg->has_vtarg*4;
+       cfg->locals_size += size;
+       cfg->locals_size += align - 1;
+       cfg->locals_size &= ~(align - 1);
 
-               g_assert ((align & 3) == 0);
-
-               SET_VARINFO (vi, type, vartype, cfg->args_size + arg_start, size);
-               g_array_append_val (cfg->varinfo, vi);
-               
-               cfg->args_size += size;
-               cfg->args_size += 3;
-               cfg->args_size &= ~3;
-               break;
-       }
-       default:
-               g_assert_not_reached ();
-       }
+       SET_VARINFO (vi, type, vartype, - cfg->locals_size, size);
+       g_array_append_val (cfg->varinfo, vi);
 
        return cfg->varinfo->len - 1;
 }
@@ -649,8 +730,8 @@ mono_label_cfg (MonoFlowGraph *cfg)
                        if (!mbstate) {
                                if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
                                        return FALSE;
-                               g_warning ("tree does not match in %s",
-                                          mono_method_full_name (cfg->method, TRUE));
+                               g_warning ("tree does not match in %s: 0x%04x",
+                                          mono_method_full_name (cfg->method, TRUE), t1->cli_addr);
                                mono_print_ctree (cfg, t1); printf ("\n\n");
 
                                mono_print_forest (cfg, forest);
@@ -1153,6 +1234,7 @@ arch_jit_compile_cfg (MonoDomain *target_domain, MonoFlowGraph *cfg)
        MonoJitInfo *ji;
        guint32 ls_used_mask = 0;
        MonoMethod *method = cfg->method;
+       int offset, gap;
 
        ji = mono_mempool_alloc0 (target_domain->mp, sizeof (MonoJitInfo));
                
@@ -1193,6 +1275,21 @@ arch_jit_compile_cfg (MonoDomain *target_domain, MonoFlowGraph *cfg)
        arch_emit_epilogue (cfg);               
        cfg->epilogue_end = cfg->code - cfg->start;
 
+       offset = cfg->code - cfg->start;
+       gap = cfg->code_size - offset;
+       if (gap > 0) {
+               char *org = cfg->start;
+#if 0
+               cfg->start = g_realloc (cfg->start, offset);
+#else
+               cfg->start = mono_mempool_alloc (target_domain->code_mp, offset);
+               memcpy (cfg->start, org, offset);
+               g_free (org);
+#endif
+               cfg->code_size = offset;
+               cfg->code = cfg->start + offset;
+       }
+
        mono_compute_branches (cfg);
 
        ji->code_size = cfg->code - cfg->start;