2007-11-17 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-x86.c
index e1a2c299943f90a4818b4c68b15f9a41162159ce..7d6ca40ab66f8d9906d8a120f6e63187e797a3e3 100644 (file)
@@ -62,6 +62,9 @@ static CRITICAL_SECTION mini_arch_mutex;
 
 #define NOT_IMPLEMENTED g_assert_not_reached ()
 
+MonoBreakpointInfo
+mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
+
 const char*
 mono_arch_regname (int reg) {
        switch (reg) {
@@ -174,7 +177,7 @@ add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
 
 
 static void
-add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
+add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
               gboolean is_return,
               guint32 *gr, guint32 *fr, guint32 *stack_size)
 {
@@ -185,7 +188,7 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
        if (sig->pinvoke) 
                size = mono_type_native_stack_size (&klass->byval_arg, NULL);
        else 
-               size = mono_type_stack_size (&klass->byval_arg, NULL);
+               size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
 
 #ifdef SMALL_STRUCTS_IN_REGS
        if (sig->pinvoke && is_return) {
@@ -239,13 +242,14 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
  * For x86 win32, see ???.
  */
 static CallInfo*
-get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
+get_call_info (MonoCompile *cfg, MonoMemPool *mp, 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;
+       MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL;
 
        if (mp)
                cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
@@ -258,6 +262,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
        /* return value */
        {
                ret_type = mono_type_get_underlying_type (sig->ret);
+               ret_type = mini_get_basic_type_from_generic (gsctx, ret_type);
                switch (ret_type->type) {
                case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_I1:
@@ -300,7 +305,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
                case MONO_TYPE_VALUETYPE: {
                        guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
 
-                       add_valuetype (sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
+                       add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
                        if (cinfo->ret.storage == ArgOnStack)
                                /* The caller passes the address where the value is stored */
                                add_general (&gr, &stack_size, &cinfo->ret);
@@ -353,6 +358,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
                        continue;
                }
                ptype = mono_type_get_underlying_type (sig->params [i]);
+               ptype = mini_get_basic_type_from_generic (gsctx, ptype);
                switch (ptype->type) {
                case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_I1:
@@ -386,7 +392,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
                        }
                        /* Fall through */
                case MONO_TYPE_VALUETYPE:
-                       add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
+                       add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
                        break;
                case MONO_TYPE_TYPEDBYREF:
                        stack_size += sizeof (MonoTypedRef);
@@ -449,7 +455,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
        int offset = 8;
        CallInfo *cinfo;
 
-       cinfo = get_call_info (NULL, csig, FALSE);
+       cinfo = get_call_info (NULL, NULL, csig, FALSE);
 
        if (MONO_TYPE_ISSTRUCT (csig->ret) && (cinfo->ret.storage == ArgOnStack)) {
                frame_size += sizeof (gpointer);
@@ -471,7 +477,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
                        size = mono_type_native_stack_size (csig->params [k], &align);
                else {
                        int ialign;
-                       size = mono_type_stack_size (csig->params [k], &ialign);
+                       size = mini_type_stack_size (NULL, csig->params [k], &ialign);
                        align = ialign;
                }
 
@@ -777,7 +783,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        header = mono_method_get_header (cfg->method);
        sig = mono_method_signature (cfg->method);
 
-       cinfo = get_call_info (cfg->mempool, sig, FALSE);
+       cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
 
        cfg->frame_reg = MONO_ARCH_BASEREG;
        offset = 0;
@@ -883,7 +889,7 @@ mono_arch_create_vars (MonoCompile *cfg)
 
        sig = mono_method_signature (cfg->method);
 
-       cinfo = get_call_info (cfg->mempool, sig, FALSE);
+       cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
 
        if (cinfo->ret.storage == ArgValuetypeInReg)
                cfg->ret_var_is_local = TRUE;
@@ -970,7 +976,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
        sig = call->signature;
        n = sig->param_count + sig->hasthis;
 
-       cinfo = get_call_info (cfg->mempool, sig, FALSE);
+       cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
 
        if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
                sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
@@ -1016,7 +1022,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                                                size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
                                        else {
                                                int ialign;
-                                               size = mono_type_stack_size (&in->klass->byval_arg, &ialign);
+                                               size = mini_type_stack_size (cfg->generic_sharing_context, &in->klass->byval_arg, &ialign);
                                                align = ialign;
                                        }
                                arg->opcode = OP_OUTARG_VT;
@@ -1948,7 +1954,7 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
        case OP_VCALL:
        case OP_VCALL_REG:
        case OP_VCALL_MEMBASE:
-               cinfo = get_call_info (cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
+               cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
                if (cinfo->ret.storage == ArgValuetypeInReg) {
                        /* Pop the destination address from the stack */
                        x86_pop_reg (code, X86_ECX);
@@ -2030,7 +2036,7 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
 
        sig = mono_method_signature (method);
 
-       cinfo = get_call_info (cfg->mempool, sig, FALSE);
+       cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
        
        /* This is the opposite of the code in emit_prolog */
 
@@ -3604,7 +3610,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        int alloc_size, pos, max_offset, i;
        guint8 *code;
 
-       cfg->code_size =  MAX (mono_method_get_header (method)->code_size * 4, 256);
+       cfg->code_size =  MAX (mono_method_get_header (method)->code_size * 4, 1024);
 
        if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
                cfg->code_size += 512;
@@ -3618,14 +3624,19 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        pos = 0;
 
        if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
-               /* Might need to attach the thread to the JIT */
-               if (lmf_tls_offset != -1) {
-                       guint8 *buf;
+               /* Might need to attach the thread to the JIT  or change the domain for the callback */
+               if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
+                       guint8 *buf, *no_domain_branch;
 
+                       code = emit_tls_get (code, X86_EAX, appdomain_tls_offset);
+                       x86_alu_reg_imm (code, X86_CMP, X86_EAX, GPOINTER_TO_UINT (cfg->domain));
+                       no_domain_branch = code;
+                       x86_branch8 (code, X86_CC_NE, 0, 0);
                        code = emit_tls_get ( code, X86_EAX, lmf_tls_offset);
                        x86_test_reg_reg (code, X86_EAX, X86_EAX);
                        buf = code;
                        x86_branch8 (code, X86_CC_NE, 0, 0);
+                       x86_patch (no_domain_branch, code);
                        x86_push_imm (code, cfg->domain);
                        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);
@@ -3909,7 +3920,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        }
 
        /* Load returned vtypes into registers if needed */
-       cinfo = get_call_info (cfg->mempool, sig, FALSE);
+       cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
        if (cinfo->ret.storage == ArgValuetypeInReg) {
                for (quad = 0; quad < 2; quad ++) {
                        switch (cinfo->ret.pair_storage [quad]) {
@@ -4119,7 +4130,7 @@ void
 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
 {
        MonoCallInst *call = (MonoCallInst*)inst;
-       CallInfo *cinfo = get_call_info (cfg->mempool, inst->signature, FALSE);
+       CallInfo *cinfo = get_call_info (cfg, cfg->mempool, inst->signature, FALSE);
 
        /* add the this argument */
        if (this_reg != -1) {
@@ -4287,7 +4298,7 @@ MonoObject*
 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
 {
        MonoMethodSignature *sig = mono_method_signature (method);
-       CallInfo *cinfo = get_call_info (NULL, sig, FALSE);
+       CallInfo *cinfo = get_call_info (NULL, NULL, sig, FALSE);
        int this_argument_offset;
        MonoObject *this_argument;
 
@@ -4339,42 +4350,6 @@ mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethod
                        ins->inst_i1 = args [1];
                }
 #endif
-       } else if (cmethod->klass == mono_defaults.thread_class &&
-                          strcmp (cmethod->name, "MemoryBarrier") == 0) {
-               MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
-       } else if(cmethod->klass->image == mono_defaults.corlib &&
-                          (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
-                          (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
-
-               if (strcmp (cmethod->name, "Increment") == 0 && fsig->params [0]->type == MONO_TYPE_I4) {
-                       MonoInst *ins_iconst;
-
-                       MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_NEW_I4);
-                       MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
-                       ins_iconst->inst_c0 = 1;
-
-                       ins->inst_i0 = args [0];
-                       ins->inst_i1 = ins_iconst;
-               } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->params [0]->type == MONO_TYPE_I4) {
-                       MonoInst *ins_iconst;
-
-                       MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_NEW_I4);
-                       MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
-                       ins_iconst->inst_c0 = -1;
-
-                       ins->inst_i0 = args [0];
-                       ins->inst_i1 = ins_iconst;
-               } else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->params [0]->type == MONO_TYPE_I4) {
-                       MONO_INST_NEW (cfg, ins, OP_ATOMIC_EXCHANGE_I4);
-
-                       ins->inst_i0 = args [0];
-                       ins->inst_i1 = args [1];
-               } else if (strcmp (cmethod->name, "Add") == 0 && fsig->params [0]->type == MONO_TYPE_I4) {
-                       MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_NEW_I4);
-
-                       ins->inst_i0 = args [0];
-                       ins->inst_i1 = args [1];
-               }
        }
 
        return ins;
@@ -4442,12 +4417,40 @@ mono_arch_get_patch_offset (guint8 *code)
        }
 }
 
-gpointer*
-mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
+gboolean
+mono_breakpoint_clean_code (guint8 *code, guint8 *buf, int size)
+{
+       int i;
+       gboolean can_write = TRUE;
+       memcpy (buf, code, size);
+       for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
+               int idx = mono_breakpoint_info_index [i];
+               guint8 *ptr;
+               if (idx < 1)
+                       continue;
+               ptr = mono_breakpoint_info [idx].address;
+               if (ptr >= code && ptr < code + size) {
+                       guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
+                       can_write = FALSE;
+                       /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
+                       buf [ptr - code] = saved_byte;
+               }
+       }
+       return can_write;
+}
+
+gpointer
+mono_arch_get_vcall_slot (guint8 *code, gpointer *regs, int *displacement)
 {
+       guint8 buf [8];
        guint8 reg = 0;
        gint32 disp = 0;
 
+       mono_breakpoint_clean_code (code - 8, buf, sizeof (buf));
+       code = buf + 8;
+
+       *displacement = 0;
+
        /* go to the start of the call instruction
         *
         * address_byte = (m << 6) | (o << 3) | reg
@@ -4501,7 +4504,19 @@ mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
                        return NULL;
        }
 
-       return (gpointer*)(((gint32)(regs [reg])) + disp);
+       *displacement = disp;
+       return regs [reg];
+}
+
+gpointer*
+mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
+{
+       gpointer vt;
+       int displacement;
+       vt = mono_arch_get_vcall_slot (code, regs, &displacement);
+       if (!vt)
+               return NULL;
+       return (gpointer*)((char*)vt + displacement);
 }
 
 gpointer
@@ -4511,7 +4526,7 @@ mono_arch_get_this_arg_from_call (MonoMethodSignature *sig, gssize *regs, guint8
        CallInfo *cinfo;
        gpointer res;
 
-       cinfo = get_call_info (NULL, sig, FALSE);
+       cinfo = get_call_info (NULL, NULL, sig, FALSE);
 
        /*
         * The stack looks like: