2007-11-28 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-x86.c
index 822881789e30507df16b70dccc1ffffc82d63965..e649ab21388b2e50c9a5bc7b7f41eca1d2120cfb 100644 (file)
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/threads.h>
 #include <mono/metadata/profiler-private.h>
+#include <mono/metadata/mono-debug.h>
 #include <mono/utils/mono-math.h>
 
 #include "trace.h"
 #include "mini-x86.h"
-#include "debug-mini.h"
 #include "inssel.h"
 #include "cpu-x86.h"
 
@@ -63,14 +63,19 @@ 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) {
+mono_arch_regname (int reg)
+{
        switch (reg) {
        case X86_EAX: return "%eax";
        case X86_EBX: return "%ebx";
        case X86_ECX: return "%ecx";
        case X86_EDX: return "%edx";
-       case X86_ESP: return "%esp";    case X86_EBP: return "%ebp";
+       case X86_ESP: return "%esp";    
+       case X86_EBP: return "%ebp";
        case X86_EDI: return "%edi";
        case X86_ESI: return "%esi";
        }
@@ -78,8 +83,28 @@ mono_arch_regname (int reg) {
 }
 
 const char*
-mono_arch_fregname (int reg) {
-       return "unknown";
+mono_arch_fregname (int reg)
+{
+       switch (reg) {
+       case 0:
+               return "%fr0";
+       case 1:
+               return "%fr1";
+       case 2:
+               return "%fr2";
+       case 3:
+               return "%fr3";
+       case 4:
+               return "%fr4";
+       case 5:
+               return "%fr5";
+       case 6:
+               return "%fr6";
+       case 7:
+               return "%fr7";
+       default:
+               return "unknown";
+       }
 }
 
 typedef enum {
@@ -2132,14 +2157,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
 
-               if (offset > (cfg->code_size - max_len - 16)) {
+               if (G_UNLIKELY (offset > (cfg->code_size - max_len - 16))) {
                        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++;
                }
 
-               mono_debug_record_line_number (cfg, ins, offset);
+               if (cfg->debug_info)
+                       mono_debug_record_line_number (cfg, ins, offset);
 
                switch (ins->opcode) {
                case OP_BIGMUL:
@@ -2200,9 +2226,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, TRUE);
                        break;
                case CEE_CONV_I1:
+               case OP_SEXT_I1:
                        x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
                        break;
                case CEE_CONV_I2:
+               case OP_SEXT_I2:
                        x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
                        break;
                case CEE_CONV_U1:
@@ -2455,12 +2483,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case CEE_NEG:
                        x86_neg_reg (code, ins->sreg1);
                        break;
-               case OP_SEXT_I1:
-                       x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
-                       break;
-               case OP_SEXT_I2:
-                       x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
-                       break;
+
                case CEE_MUL:
                        x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
                        break;
@@ -2785,6 +2808,25 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
 #endif
                        break;
+               case OP_START_HANDLER: {
+                       MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+                       x86_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, X86_ESP, 4);
+                       break;
+               }
+               case OP_ENDFINALLY: {
+                       MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+                       x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
+                       x86_ret (code);
+                       break;
+               }
+               case OP_ENDFILTER: {
+                       MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+                       x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
+                       /* The local allocator will put the result into EAX */
+                       x86_ret (code);
+                       break;
+               }
+
                case OP_LABEL:
                        ins->inst_c0 = code - cfg->native_code;
                        break;
@@ -3622,14 +3664,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);
@@ -4343,42 +4390,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;
@@ -4446,65 +4457,36 @@ mono_arch_get_patch_offset (guint8 *code)
        }
 }
 
-struct _MonoDebuggerBreakpointInfo {
-       const guint8 *address;
-       guint8 saved_byte;
-};
-
-static MonoDebuggerBreakpointInfo breakpoint_info_area [MONO_DEBUGGER_BREAKPOINT_TABLE_SIZE];
-static volatile const MonoDebuggerBreakpointInfo *breakpoint_table [MONO_DEBUGGER_BREAKPOINT_TABLE_SIZE];
-
-volatile const MonoDebuggerBreakpointInfo *_mono_debugger_breakpoint_info_area = breakpoint_info_area;
-volatile const MonoDebuggerBreakpointInfo **mono_debugger_breakpoint_table = breakpoint_table;
-
-/*
- * Removes breakpoints from target memory.
- *
- * @orig_address:
- * The original memory address.
- *
- * @code:
- * A copy of @size bytes from that memory area, which we can modify.
- *
- * Returns:
- * TRUE if there were any breakpoints in that area, FALSE if not.
- */
 gboolean
-mono_debugger_remove_breakpoints_from_code (const guint8 *orig_address, guint8 *code, int size)
+mono_breakpoint_clean_code (guint8 *code, guint8 *buf, int size)
 {
-       gboolean found_breakpoint = FALSE;
        int i;
-
-       for (i = 0; i < MONO_DEBUGGER_BREAKPOINT_TABLE_SIZE; i++) {
-               volatile const MonoDebuggerBreakpointInfo *info = mono_debugger_breakpoint_table [i];
-               int offset;
-
-               if (!info)
-                       continue;
-
-               if ((info->address < orig_address) || (info->address > orig_address + size))
+       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;
-
-               if (!found_breakpoint) {
-                       memcpy (code, orig_address, size);
-                       found_breakpoint = TRUE;
+               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;
                }
-
-               offset = info->address - orig_address;
-               code [offset] = info->saved_byte;
        }
-
-       return found_breakpoint;
+       return can_write;
 }
 
 gpointer
 mono_arch_get_vcall_slot (guint8 *code, gpointer *regs, int *displacement)
 {
-       guint8 buf [16];
+       guint8 buf [8];
        guint8 reg = 0;
        gint32 disp = 0;
 
-       mono_debugger_remove_breakpoints_from_code (code - 8, buf, sizeof (buf));
+       mono_breakpoint_clean_code (code - 8, buf, sizeof (buf));
        code = buf + 8;
 
        *displacement = 0;
@@ -4638,7 +4620,7 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
                g_assert ((code - start) < 64);
 
                cached = start;
-
+               mono_debug_add_delegate_trampoline (start, code - start);
                mono_mini_arch_unlock ();
        } else {
                static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
@@ -4690,6 +4672,7 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
 
                cache [sig->param_count] = start;
 
+               mono_debug_add_delegate_trampoline (start, code - start);
                mono_mini_arch_unlock ();
        }