2009-12-26 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-x86.c
index 819eb99cbac63e40b447311ea4cef17a1f0bb04a..40ab916edccf072c3c298ac4d3526d66254448f4 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;
@@ -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);
@@ -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,7 @@ 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;
@@ -2369,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 ().
@@ -4514,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));
@@ -4577,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));
@@ -4634,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);
@@ -5027,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.
@@ -5193,28 +5218,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*
@@ -5433,6 +5436,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)
@@ -5822,9 +5848,12 @@ mono_arch_stop_single_stepping (void)
 gboolean
 mono_arch_is_single_step_event (void *info, void *sigctx)
 {
-#ifdef PLATFORM_WIN32
-       EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;
-       return FALSE;
+#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 */
@@ -5838,9 +5867,12 @@ mono_arch_is_single_step_event (void *info, void *sigctx)
 gboolean
 mono_arch_is_breakpoint_event (void *info, void *sigctx)
 {
-#ifdef PLATFORM_WIN32
-       EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info;
-       return FALSE;
+#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 */