2010-02-10 Miguel de Icaza <miguel@novell.com>
[mono.git] / mono / mini / mini-x86.c
index e4b9f11af37fb9497d7c668b6e9081ef7948faed..b5377dce8fa5223b688784bc4873039d592ea6a5 100644 (file)
@@ -40,7 +40,7 @@ static gboolean optimize_for_xen = TRUE;
 #define optimize_for_xen 0
 #endif
 
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
 static gboolean is_win32 = TRUE;
 #else
 static gboolean is_win32 = FALSE;
@@ -55,7 +55,7 @@ static CRITICAL_SECTION mini_arch_mutex;
 
 #define ARGS_OFFSET 8
 
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
 /* Under windows, the default pinvoke calling convention is stdcall */
 #define CALLCONV_IS_STDCALL(sig) ((((sig)->call_convention) == MONO_CALL_STDCALL) || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_DEFAULT))
 #else
@@ -180,7 +180,7 @@ typedef struct {
 
 static X86_Reg_No param_regs [] = { 0 };
 
-#if defined(PLATFORM_WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
+#if defined(TARGET_WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
 #define SMALL_STRUCTS_IN_REGS
 static X86_Reg_No return_regs [] = { X86_EAX, X86_EDX };
 #endif
@@ -296,18 +296,12 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
  * For x86 win32, see ???.
  */
 static CallInfo*
-get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
+get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoMethodSignature *sig, gboolean is_pinvoke)
 {
        guint32 i, gr, fr;
        MonoType *ret_type;
        int n = sig->hasthis + sig->param_count;
        guint32 stack_size = 0;
-       CallInfo *cinfo;
-
-       if (mp)
-               cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
-       else
-               cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
 
        gr = 0;
        fr = 0;
@@ -348,7 +342,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
                        cinfo->ret.storage = ArgOnDoubleFpStack;
                        break;
                case MONO_TYPE_GENERICINST:
-                       if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
+                       if (!mono_type_generic_inst_is_valuetype (ret_type)) {
                                cinfo->ret.storage = ArgInIReg;
                                cinfo->ret.reg = X86_EAX;
                                break;
@@ -437,7 +431,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
                        add_general (&gr, &stack_size, ainfo);
                        break;
                case MONO_TYPE_GENERICINST:
-                       if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
+                       if (!mono_type_generic_inst_is_valuetype (ptype)) {
                                add_general (&gr, &stack_size, ainfo);
                                break;
                        }
@@ -485,6 +479,20 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
        return cinfo;
 }
 
+static CallInfo*
+get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
+{
+       int n = sig->hasthis + sig->param_count;
+       CallInfo *cinfo;
+
+       if (mp)
+               cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
+       else
+               cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
+
+       return get_call_info_internal (gsctx, cinfo, sig, is_pinvoke);
+}
+
 /*
  * mono_arch_get_argument_info:
  * @csig:  a method signature
@@ -495,6 +503,9 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
  * padding. arg_info should be large enought to hold param_count + 1 entries. 
  *
  * Returns the size of the argument area on the stack.
+ * This should be signal safe, since it is called from
+ * mono_arch_find_jit_info_ext ().
+ * FIXME: The metadata calls might not be signal safe.
  */
 int
 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
@@ -505,7 +516,10 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
        int offset = 8;
        CallInfo *cinfo;
 
-       cinfo = get_call_info (NULL, NULL, csig, FALSE);
+       /* Avoid g_malloc as it is not signal safe */
+       cinfo = (CallInfo*)g_newa (guint8*, sizeof (CallInfo) + (sizeof (ArgInfo) * (csig->param_count + 1)));
+
+       cinfo = get_call_info_internal (NULL, cinfo, csig, FALSE);
 
        if (MONO_TYPE_ISSTRUCT (csig->ret) && (cinfo->ret.storage == ArgOnStack)) {
                args_size += sizeof (gpointer);
@@ -544,8 +558,6 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
        args_size += pad = (align - (args_size & (align - 1))) & (align - 1);
        arg_info [k].pad = pad;
 
-       g_free (cinfo);
-
        return args_size;
 }
 
@@ -990,6 +1002,13 @@ mono_arch_allocate_vars (MonoCompile *cfg)
 
        /* Allocate locals */
        offsets = mono_allocate_stack_slots (cfg, &locals_stack_size, &locals_stack_align);
+       if (locals_stack_size > MONO_ARCH_MAX_FRAME_SIZE) {
+               char *mname = mono_method_full_name (cfg->method, TRUE);
+               cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+               cfg->exception_message = g_strdup_printf ("Method %s stack is too big.", mname);
+               g_free (mname);
+               return;
+       }
        if (locals_stack_align) {
                offset += (locals_stack_align - 1);
                offset &= ~(locals_stack_align - 1);
@@ -1143,7 +1162,6 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
        int i, n;
        CallInfo *cinfo;
        ArgInfo *ainfo;
-       int j;
        LLVMCallInfo *linfo;
 
        n = sig->param_count + sig->hasthis;
@@ -1486,8 +1504,9 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea
        guchar *code = p;
        int arg_size = 0, stack_usage = 0, save_mode = SAVE_NONE;
        MonoMethod *method = cfg->method;
-       
-       switch (mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type) {
+       MonoType *ret_type = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
+
+       switch (ret_type->type) {
        case MONO_TYPE_VOID:
                /* special case string .ctor icall */
                if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class) {
@@ -1507,7 +1526,7 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea
                stack_usage = enable_arguments ? 16 : 8;
                break;
        case MONO_TYPE_GENERICINST:
-               if (!mono_type_generic_inst_is_valuetype (mono_method_signature (method)->ret)) {
+               if (!mono_type_generic_inst_is_valuetype (ret_type)) {
                        save_mode = SAVE_EAX;
                        stack_usage = enable_arguments ? 8 : 4;
                        break;
@@ -1890,7 +1909,7 @@ mono_emit_stack_alloc (guchar *code, MonoInst* tree)
        int sreg = tree->sreg1;
        int need_touch = FALSE;
 
-#if defined(PLATFORM_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
+#if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
        need_touch = TRUE;
 #endif
 
@@ -2025,7 +2044,7 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
 guint8*
 mono_x86_emit_tls_get (guint8* code, int dreg, int tls_offset)
 {
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
        /* 
         * See the Under the Hood article in the May 1996 issue of Microsoft Systems 
         * Journal and/or a disassembly of the TlsGet () function.
@@ -2355,7 +2374,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_NULL:
                        break;
                case OP_SEQ_POINT: {
-                       int i, il_offset;
+                       int i;
+
+                       if (cfg->compile_aot)
+                               NOT_IMPLEMENTED;
 
                        /* 
                         * Read from the single stepping trigger page. This will cause a
@@ -2366,12 +2388,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ins->flags & MONO_INST_SINGLE_STEP_LOC)
                                x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)ss_trigger_page);
 
-                       il_offset = ins->inst_imm;
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
 
-                       if (!cfg->seq_points)
-                               cfg->seq_points = g_ptr_array_new ();
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (il_offset));
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (code - cfg->native_code));
                        /* 
                         * A placeholder for a possible breakpoint inserted by
                         * mono_arch_set_breakpoint ().
@@ -4511,7 +4529,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
                        x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
                        x86_patch (buf, code);
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
                        /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
                        /* FIXME: Add a separate key for LMF to avoid this */
                        x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
@@ -4574,7 +4592,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        if (lmf_addr_tls_offset != -1) {
                                /* Load lmf quicky using the GS register */
                                code = mono_x86_emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
                                /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
                                /* FIXME: Add a separate key for LMF to avoid this */
                                x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
@@ -4631,8 +4649,18 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 
        if (alloc_size) {
                /* See mono_emit_stack_alloc */
-#if defined(PLATFORM_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
+#if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
                guint32 remaining_size = alloc_size;
+               /*FIXME handle unbounded code expansion, we should use a loop in case of more than X interactions*/
+               guint32 required_code_size = ((remaining_size / 0x1000) + 1) * 8; /*8 is the max size of x86_alu_reg_imm + x86_test_membase_reg*/
+               guint32 offset = code - cfg->native_code;
+               if (G_UNLIKELY (required_code_size >= (cfg->code_size - offset))) {
+                       while (required_code_size >= (cfg->code_size - offset))
+                               cfg->code_size *= 2;
+                       cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
+                       code = cfg->native_code + offset;
+                       mono_jit_stats.code_reallocs++;
+               }
                while (remaining_size >= 0x1000) {
                        x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
                        x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
@@ -5024,7 +5052,7 @@ mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
 {
        if (!tls_offset_inited) {
                if (!getenv ("MONO_NO_TLS")) {
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
                        /* 
                         * We need to init this multiple times, since when we are first called, the key might not
                         * be initialized yet.
@@ -5068,6 +5096,7 @@ mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
 #define BR_LARGE_SIZE 5
 #define JUMP_IMM_SIZE 6
 #define ENABLE_WRONG_METHOD_CHECK 0
+#define DEBUG_IMT 0
 
 static int
 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
@@ -5182,6 +5211,15 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        if (!fail_tramp)
                mono_stats.imt_thunks_size += code - start;
        g_assert (code - start <= size);
+
+#if DEBUG_IMT
+       {
+               char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
+               mono_disassemble_code (NULL, (guint8*)start, code - start, buff);
+               g_free (buff);
+       }
+#endif
+
        return start;
 }
 
@@ -5190,28 +5228,6 @@ mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
 {
        return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
 }
-
-MonoObject*
-mono_arch_find_this_argument (mgreg_t *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
-{
-       MonoMethodSignature *sig = mono_method_signature (method);
-       CallInfo *cinfo = get_call_info (gsctx, NULL, sig, FALSE);
-       int this_argument_offset;
-       MonoObject *this_argument;
-
-       /* 
-        * this is the offset of the this arg from esp as saved at the start of 
-        * mono_arch_create_trampoline_code () in tramp-x86.c.
-        */
-       this_argument_offset = 5;
-       if (MONO_TYPE_ISSTRUCT (sig->ret) && (cinfo->ret.storage == ArgOnStack))
-               this_argument_offset++;
-
-       this_argument = * (MonoObject**) (((guint8*) regs [X86_ESP]) + this_argument_offset * sizeof (gpointer));
-
-       g_free (cinfo);
-       return this_argument;
-}
 #endif
 
 MonoVTable*
@@ -5430,6 +5446,29 @@ mono_arch_get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement)
        return (gpointer)regs [reg];
 }
 
+/*
+ * mono_x86_get_this_arg_offset:
+ *
+ *   Return the offset of the stack location where this is passed during a virtual
+ * call.
+ */
+guint32
+mono_x86_get_this_arg_offset (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
+{
+       CallInfo *cinfo = NULL;
+       int offset;
+
+       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+               cinfo = get_call_info (gsctx, NULL, sig, FALSE);
+
+               offset = cinfo->args [0].offset;
+       } else {
+               offset = 0;
+       }
+
+       return offset;
+}
+
 gpointer
 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig,
                mgreg_t *regs, guint8 *code)
@@ -5817,23 +5856,41 @@ mono_arch_stop_single_stepping (void)
  * step event.
  */
 gboolean
-mono_arch_is_single_step_event (siginfo_t *info, void *sigctx)
+mono_arch_is_single_step_event (void *info, void *sigctx)
 {
+#ifdef TARGET_WIN32
+       EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;      /* Sometimes the address is off by 4 */
+       if ((einfo->ExceptionInformation[1] >= ss_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)ss_trigger_page + 128))
+               return TRUE;
+       else
+               return FALSE;
+#else
+       siginfo_t* sinfo = (siginfo_t*) info;
        /* Sometimes the address is off by 4 */
-       if (info->si_signo == DBG_SIGNAL && (info->si_addr >= ss_trigger_page && (guint8*)info->si_addr <= (guint8*)ss_trigger_page + 128))
+       if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128))
                return TRUE;
        else
                return FALSE;
+#endif
 }
 
 gboolean
-mono_arch_is_breakpoint_event (siginfo_t *info, void *sigctx)
+mono_arch_is_breakpoint_event (void *info, void *sigctx)
 {
+#ifdef TARGET_WIN32
+       EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;      /* Sometimes the address is off by 4 */
+       if ((einfo->ExceptionInformation[1] >= bp_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)bp_trigger_page + 128))
+               return TRUE;
+       else
+               return FALSE;
+#else
+       siginfo_t* sinfo = (siginfo_t*)info;
        /* Sometimes the address is off by 4 */
-       if (info->si_signo == DBG_SIGNAL && (info->si_addr >= bp_trigger_page && (guint8*)info->si_addr <= (guint8*)bp_trigger_page + 128))
+       if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128))
                return TRUE;
        else
                return FALSE;
+#endif
 }
 
 /*