X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-x86.c;h=4809ae935bd8d98854070c2abf7c463bea840056;hb=8170bf67b1e630a8eb7d3fa0cb7c191c38f5c663;hp=a7abb8871295253d2edf10a64cafa3fd6f66739d;hpb=92f60fbffa1187be7dedf6a9286b5c35b2082815;p=mono.git diff --git a/mono/mini/mini-x86.c b/mono/mini/mini-x86.c index a7abb887129..4809ae935bd 100644 --- a/mono/mini/mini-x86.c +++ b/mono/mini/mini-x86.c @@ -6,7 +6,9 @@ * Dietmar Maurer (dietmar@ximian.com) * Patrik Torstensson * - * (C) 2003 Ximian, Inc. + * Copyright 2003 Ximian, Inc. + * Copyright 2003-2011 Novell Inc. + * Copyright 2011 Xamarin Inc. */ #include "mini.h" #include @@ -24,11 +26,13 @@ #include #include #include +#include #include "trace.h" #include "mini-x86.h" #include "cpu-x86.h" #include "ir-emit.h" +#include "mini-gc.h" /* On windows, these hold the key returned by TlsAlloc () */ static gint lmf_tls_offset = -1; @@ -63,40 +67,17 @@ static CRITICAL_SECTION mini_arch_mutex; #define CALLCONV_IS_STDCALL(sig) (((sig)->call_convention) == MONO_CALL_STDCALL) #endif +#define X86_IS_CALLEE_SAVED_REG(reg) (((reg) == X86_EBX) || ((reg) == X86_EDI) || ((reg) == X86_ESI)) + MonoBreakpointInfo mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE]; -static gpointer -mono_realloc_native_code (MonoCompile *cfg) -{ -#ifdef __native_client_codegen__ - guint old_padding; - gpointer native_code; - guint alignment_check; - - /* Save the old alignment offset so we can re-align after the realloc. */ - old_padding = (guint)(cfg->native_code - cfg->native_code_alloc); - - cfg->native_code_alloc = g_realloc (cfg->native_code_alloc, - cfg->code_size + kNaClAlignment); - - /* Align native_code to next nearest kNaClAlignment byte. */ - native_code = (guint)cfg->native_code_alloc + kNaClAlignment; - native_code = (guint)native_code & ~kNaClAlignmentMask; - - /* Shift the data to be 32-byte aligned again. */ - memmove (native_code, cfg->native_code_alloc + old_padding, cfg->code_size); - - alignment_check = (guint)native_code & kNaClAlignmentMask; - g_assert (alignment_check == 0); - return native_code; -#else - return g_realloc (cfg->native_code, cfg->code_size); -#endif -} #ifdef __native_client_codegen__ +/* Default alignment for Native Client is 32-byte. */ +gint8 nacl_align_byte = -32; /* signed version of 0xe0 */ + /* mono_arch_nacl_pad: Add pad bytes of alignment instructions at code, */ /* Check that alignment doesn't cross an alignment boundary. */ guint8 * @@ -221,6 +202,8 @@ typedef struct { gint16 offset; gint8 reg; ArgStorage storage; + int nslots; + gboolean is_pair; /* Only if storage == ArgValuetypeInReg */ ArgStorage pair_storage [2]; @@ -237,6 +220,7 @@ typedef struct { gboolean vtype_retaddr; /* The index of the vret arg in the argument list */ int vret_arg_index; + int vret_arg_offset; ArgInfo ret; ArgInfo sig_cookie; ArgInfo args [1]; @@ -278,6 +262,7 @@ add_general_pair (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo) ainfo->storage = ArgOnStack; (*stack_size) += sizeof (gpointer) * 2; + ainfo->nslots = 2; } static void inline @@ -288,6 +273,7 @@ add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double) if (*gr >= FLOAT_PARAM_REGS) { ainfo->storage = ArgOnStack; (*stack_size) += is_double ? 8 : 4; + ainfo->nslots = is_double ? 2 : 1; } else { /* A double register */ @@ -352,6 +338,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn ainfo->offset = *stack_size; ainfo->storage = ArgOnStack; *stack_size += ALIGN_TO (size, sizeof (gpointer)); + ainfo->nslots = ALIGN_TO (size, sizeof (gpointer)) / sizeof (gpointer); } /* @@ -364,15 +351,17 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn * For x86 win32, see ???. */ static CallInfo* -get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoMethodSignature *sig, gboolean is_pinvoke) +get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoMethodSignature *sig) { guint32 i, gr, fr, pstart; MonoType *ret_type; int n = sig->hasthis + sig->param_count; guint32 stack_size = 0; + gboolean is_pinvoke = sig->pinvoke; gr = 0; fr = 0; + cinfo->nargs = n; /* return value */ { @@ -402,6 +391,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM case MONO_TYPE_I8: cinfo->ret.storage = ArgInIReg; cinfo->ret.reg = X86_EAX; + cinfo->ret.is_pair = TRUE; break; case MONO_TYPE_R4: cinfo->ret.storage = ArgOnFloatFpStack; @@ -416,7 +406,8 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM break; } /* Fall through */ - case MONO_TYPE_VALUETYPE: { + case MONO_TYPE_VALUETYPE: + case MONO_TYPE_TYPEDBYREF: { guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0; add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize); @@ -426,10 +417,6 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM } break; } - case MONO_TYPE_TYPEDBYREF: - /* Same as a valuetype with size 12 */ - cinfo->vtype_retaddr = TRUE; - break; case MONO_TYPE_VOID: cinfo->ret.storage = ArgNone; break; @@ -453,6 +440,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0]); pstart = 1; } + cinfo->vret_arg_offset = stack_size; add_general (&gr, &stack_size, &cinfo->ret); cinfo->vret_arg_index = 1; } else { @@ -527,11 +515,8 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM } /* Fall through */ case MONO_TYPE_VALUETYPE: - add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size); - break; case MONO_TYPE_TYPEDBYREF: - stack_size += sizeof (MonoTypedRef); - ainfo->storage = ArgOnStack; + add_valuetype (gsctx, sig, ainfo, ptype, FALSE, &gr, &fr, &stack_size); break; case MONO_TYPE_U8: case MONO_TYPE_I8: @@ -570,7 +555,7 @@ get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoM } static CallInfo* -get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke) +get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig) { int n = sig->hasthis + sig->param_count; CallInfo *cinfo; @@ -580,7 +565,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign else cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n)); - return get_call_info_internal (gsctx, cinfo, sig, is_pinvoke); + return get_call_info_internal (gsctx, cinfo, sig); } /* @@ -594,11 +579,11 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign * * 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 (). + * mono_arch_find_jit_info (). * FIXME: The metadata calls might not be signal safe. */ int -mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info) +mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info) { int len, k, args_size = 0; int size, pad; @@ -611,16 +596,22 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit cinfo = (CallInfo*)g_newa (guint8*, len); memset (cinfo, 0, len); - cinfo = get_call_info_internal (NULL, cinfo, csig, FALSE); + cinfo = get_call_info_internal (gsctx, cinfo, csig); arg_info [0].offset = offset; + if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 0) { + args_size += sizeof (gpointer); + offset += 4; + } + if (csig->hasthis) { args_size += sizeof (gpointer); offset += 4; } - if (MONO_TYPE_ISSTRUCT (csig->ret) && (cinfo->ret.storage == ArgOnStack)) { + if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 1 && csig->hasthis) { + /* Emitted after this */ args_size += sizeof (gpointer); offset += 4; } @@ -641,6 +632,12 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit offset += pad; arg_info [k + 1].offset = offset; offset += size; + + if (k == 0 && cinfo->vtype_retaddr && cinfo->vret_arg_index == 1 && !csig->hasthis) { + /* Emitted after the first arg */ + args_size += sizeof (gpointer); + offset += 4; + } } if (mono_do_x86_stack_align && !CALLCONV_IS_STDCALL (csig)) @@ -653,6 +650,26 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit return args_size; } +gboolean +mono_x86_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig) +{ + CallInfo *c1, *c2; + gboolean res; + + c1 = get_call_info (NULL, NULL, caller_sig); + c2 = get_call_info (NULL, NULL, callee_sig); + res = c1->stack_usage >= c2->stack_usage; + if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret) && c2->ret.storage != ArgValuetypeInReg) + /* An address on the callee's stack is passed as the first argument */ + res = FALSE; + + g_free (c1); + g_free (c2); + + return res; +} + +#if !defined(__native_client__) static const guchar cpuid_impl [] = { 0x55, /* push %ebp */ 0x89, 0xe5, /* mov %esp,%ebp */ @@ -673,6 +690,33 @@ static const guchar cpuid_impl [] = { 0xc9, /* leave */ 0xc3, /* ret */ }; +#else +static const guchar cpuid_impl [] = { + 0x55, /* push %ebp */ + 0x89, 0xe5, /* mov %esp,%ebp */ + 0x53, /* push %ebx */ + 0x8b, 0x45, 0x08, /* mov 0x8(%ebp),%eax */ + 0x0f, 0xa2, /* cpuid */ + 0x50, /* push %eax */ + 0x8b, 0x45, 0x10, /* mov 0x10(%ebp),%eax */ + 0x89, 0x18, /* mov %ebx,(%eax) */ + 0x8b, 0x45, 0x14, /* mov 0x14(%ebp),%eax */ + 0x89, 0x08, /* mov %ecx,(%eax) */ + 0x8b, 0x45, 0x18, /* mov 0x18(%ebp),%eax */ + 0x89, 0x10, /* mov %edx,(%eax) */ + 0x58, /* pop %eax */ + 0x8b, 0x55, 0x0c, /* mov 0xc(%ebp),%edx */ + 0x89, 0x02, /* mov %eax,(%edx) */ + 0x5b, /* pop %ebx */ + 0xc9, /* leave */ + 0x59, 0x83, 0xe1, 0xe0, 0xff, 0xe1, /* naclret */ + 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, /* padding, to provide bundle aligned version */ + 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4 +}; +#endif typedef void (*CpuidFunc) (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx); @@ -680,12 +724,16 @@ static int cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx) { #if defined(__native_client__) - /* Taken from below, the bug listed in the comment is */ - /* only valid for non-static cases. */ - __asm__ __volatile__ ("cpuid" - : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx) - : "a" (id)); - return 1; + static CpuidFunc func = NULL; + void *ptr, *end_ptr; + if (!func) { + ptr = mono_global_codeman_reserve (sizeof (cpuid_impl)); + memcpy(ptr, cpuid_impl, sizeof(cpuid_impl)); + end_ptr = ptr + sizeof(cpuid_impl); + nacl_global_codeman_validate (&ptr, sizeof(cpuid_impl), &end_ptr); + func = (CpuidFunc)ptr; + } + func (id, p_eax, p_ebx, p_ecx, p_edx); #else int have_cpuid = 0; #ifndef _MSC_VER @@ -778,6 +826,9 @@ mono_arch_init (void) mono_aot_register_jit_icall ("mono_x86_throw_exception", mono_x86_throw_exception); mono_aot_register_jit_icall ("mono_x86_throw_corlib_exception", mono_x86_throw_corlib_exception); +#if defined(MONOTOUCH) || defined(MONO_EXTENSIONS) + mono_aot_register_jit_icall ("mono_x86_start_gsharedvt_call", mono_x86_start_gsharedvt_call); +#endif } /* @@ -786,6 +837,10 @@ mono_arch_init (void) void mono_arch_cleanup (void) { + if (ss_trigger_page) + mono_vfree (ss_trigger_page, mono_pagesize ()); + if (bp_trigger_page) + mono_vfree (bp_trigger_page, mono_pagesize ()); DeleteCriticalSection (&mini_arch_mutex); } @@ -793,7 +848,7 @@ mono_arch_cleanup (void) * This function returns the optimizations supported on this cpu. */ guint32 -mono_arch_cpu_optimizazions (guint32 *exclude_mask) +mono_arch_cpu_optimizations (guint32 *exclude_mask) { #if !defined(__native_client__) int eax, ebx, ecx, edx; @@ -1082,7 +1137,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) header = cfg->header; sig = mono_method_signature (cfg->method); - cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE); + cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig); cfg->frame_reg = X86_EBP; offset = 0; @@ -1118,7 +1173,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) } /* Allocate locals */ - offsets = mono_allocate_stack_slots (cfg, &locals_stack_size, &locals_stack_align); + offsets = mono_allocate_stack_slots (cfg, TRUE, &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; @@ -1127,9 +1182,18 @@ mono_arch_allocate_vars (MonoCompile *cfg) return; } if (locals_stack_align) { + int prev_offset = offset; + offset += (locals_stack_align - 1); offset &= ~(locals_stack_align - 1); + + while (prev_offset < offset) { + prev_offset += 4; + mini_gc_set_slot_type_from_fp (cfg, - prev_offset, SLOT_NOREF); + } } + cfg->locals_min_stack_offset = - (offset + locals_stack_size); + cfg->locals_max_stack_offset = - offset; /* * EBP is at alignment 8 % MONO_ARCH_FRAME_ALIGNMENT, so if we * have locals larger than 8 bytes we need to make sure that @@ -1155,7 +1219,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) switch (cinfo->ret.storage) { case ArgOnStack: - if (MONO_TYPE_ISSTRUCT (sig->ret)) { + if (cfg->vret_addr) { /* * In the new IR, the cfg->vret_addr variable represents the * vtype return value. @@ -1214,13 +1278,15 @@ mono_arch_create_vars (MonoCompile *cfg) sig = mono_method_signature (cfg->method); - cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE); + cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig); if (cinfo->ret.storage == ArgValuetypeInReg) cfg->ret_var_is_local = TRUE; - if ((cinfo->ret.storage != ArgValuetypeInReg) && MONO_TYPE_ISSTRUCT (sig->ret)) { + if ((cinfo->ret.storage != ArgValuetypeInReg) && (MONO_TYPE_ISSTRUCT (sig->ret) || mini_is_gsharedvt_variable_type (cfg, sig->ret))) { cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG); } + + cfg->arch_eh_jit_info = 1; } /* @@ -1254,9 +1320,7 @@ static void emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) { MonoMethodSignature *tmp_sig; - - /* FIXME: Add support for signature tokens to AOT */ - cfg->disable_aot = TRUE; + int sig_reg; /* * mono_ArgIterator_Setup assumes the signature cookie is @@ -1269,7 +1333,13 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) tmp_sig->sentinelpos = 0; memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*)); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_X86_PUSH_IMM, -1, -1, tmp_sig); + if (cfg->compile_aot) { + sig_reg = mono_alloc_ireg (cfg); + MONO_EMIT_NEW_SIGNATURECONST (cfg, sig_reg, tmp_sig); + MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, sig_reg); + } else { + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_X86_PUSH_IMM, -1, -1, tmp_sig); + } } #ifdef ENABLE_LLVM @@ -1284,7 +1354,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) n = sig->param_count + sig->hasthis; - cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, sig->pinvoke); + cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig); linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n)); @@ -1310,13 +1380,13 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) */ } - if (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage == ArgInIReg) { + if (mini_type_is_vtype (cfg, sig->ret) && cinfo->ret.storage == ArgInIReg) { /* Vtype returned using a hidden argument */ linfo->ret.storage = LLVMArgVtypeRetAddr; linfo->vret_arg_index = cinfo->vret_arg_index; } - if (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage != ArgInIReg) { + if (mini_type_is_vtype (cfg, sig->ret) && cinfo->ret.storage != ArgInIReg) { // FIXME: cfg->exception_message = g_strdup ("vtype ret in call"); cfg->disable_llvm = TRUE; @@ -1341,7 +1411,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) linfo->args [i].storage = LLVMArgInFPReg; break; case ArgOnStack: - if (MONO_TYPE_ISSTRUCT (t)) { + if (mini_type_is_vtype (cfg, t)) { if (mono_class_value_size (mono_class_from_mono_type (t), NULL) == 0) /* LLVM seems to allocate argument space for empty structures too */ linfo->args [i].storage = LLVMArgNone; @@ -1383,19 +1453,32 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) } #endif +static void +emit_gc_param_slot_def (MonoCompile *cfg, int sp_offset, MonoType *t) +{ + if (cfg->compute_gc_maps) { + MonoInst *def; + + /* On x86, the offsets are from the sp value before the start of the call sequence */ + if (t == NULL) + t = &mono_defaults.int_class->byval_arg; + EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF (cfg, def, sp_offset, t); + } +} + void mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) { MonoInst *arg, *in; MonoMethodSignature *sig; - int i, n; + int i, j, n; CallInfo *cinfo; - int sentinelpos = 0; + int sentinelpos = 0, sp_offset = 0; sig = call->signature; n = sig->param_count + sig->hasthis; - cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE); + cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig); if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) sentinelpos = sig->sentinelpos + (sig->hasthis ? 1 : 0); @@ -1406,6 +1489,11 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) arg->sreg1 = X86_ESP; arg->inst_imm = cinfo->stack_align_amount; MONO_ADD_INS (cfg->cbb, arg); + for (i = 0; i < cinfo->stack_align_amount; i += sizeof (mgreg_t)) { + sp_offset += 4; + + emit_gc_param_slot_def (cfg, sp_offset, NULL); + } } if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) { @@ -1421,15 +1509,20 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) } } + // FIXME: Emit EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF everywhere + /* Handle the case where there are no implicit arguments */ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sentinelpos)) { emit_sig_cookie (cfg, call, cinfo); + sp_offset += 4; + emit_gc_param_slot_def (cfg, sp_offset, NULL); } /* Arguments are pushed in the reverse order */ for (i = n - 1; i >= 0; i --) { ArgInfo *ainfo = cinfo->args + i; - MonoType *t; + MonoType *orig_type, *t; + int argsize; if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 1 && i == 0) { /* Push the vret arg before the first argument */ @@ -1438,12 +1531,15 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) vtarg->type = STACK_MP; vtarg->sreg1 = call->vret_var->dreg; MONO_ADD_INS (cfg->cbb, vtarg); + sp_offset += 4; + emit_gc_param_slot_def (cfg, sp_offset, NULL); } if (i >= sig->hasthis) t = sig->params [i - sig->hasthis]; else t = &mono_defaults.int_class->byval_arg; + orig_type = t; t = mini_type_get_underlying_type (cfg->generic_sharing_context, t); MONO_INST_NEW (cfg, arg, OP_X86_PUSH); @@ -1476,9 +1572,12 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) arg->backend.size = size; MONO_ADD_INS (cfg->cbb, arg); + sp_offset += size; + emit_gc_param_slot_def (cfg, sp_offset, orig_type); } - } - else { + } else { + argsize = 4; + switch (ainfo->storage) { case ArgOnStack: arg->opcode = OP_X86_PUSH; @@ -1488,14 +1587,17 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) arg->opcode = OP_STORER4_MEMBASE_REG; arg->inst_destbasereg = X86_ESP; arg->inst_offset = 0; + argsize = 4; } else if (t->type == MONO_TYPE_R8) { MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 8); arg->opcode = OP_STORER8_MEMBASE_REG; arg->inst_destbasereg = X86_ESP; arg->inst_offset = 0; + argsize = 8; } else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8) { arg->sreg1 ++; MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, in->dreg + 2); + sp_offset += 4; } } break; @@ -1504,15 +1606,39 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) } MONO_ADD_INS (cfg->cbb, arg); + + sp_offset += argsize; + + if (cfg->compute_gc_maps) { + if (argsize == 4) { + /* FIXME: The == STACK_OBJ check might be fragile ? */ + if (sig->hasthis && i == 0 && call->args [i]->type == STACK_OBJ) { + /* this */ + if (call->need_unbox_trampoline) + /* The unbox trampoline transforms this into a managed pointer */ + emit_gc_param_slot_def (cfg, sp_offset, &mono_defaults.int_class->this_arg); + else + emit_gc_param_slot_def (cfg, sp_offset, &mono_defaults.object_class->byval_arg); + } else { + emit_gc_param_slot_def (cfg, sp_offset, orig_type); + } + } else { + /* i8/r8 */ + for (j = 0; j < argsize; j += 4) + emit_gc_param_slot_def (cfg, sp_offset - j, NULL); + } + } } if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sentinelpos)) { /* Emit the signature cookie just before the implicit arguments */ emit_sig_cookie (cfg, call, cinfo); + sp_offset += 4; + emit_gc_param_slot_def (cfg, sp_offset, NULL); } } - if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) { + if (sig->ret && (MONO_TYPE_ISSTRUCT (sig->ret) || cinfo->vtype_retaddr)) { MonoInst *vtarg; if (cinfo->ret.storage == ArgValuetypeInReg) { @@ -1533,6 +1659,8 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) vtarg->type = STACK_MP; vtarg->sreg1 = call->vret_var->dreg; MONO_ADD_INS (cfg->cbb, vtarg); + sp_offset += 4; + emit_gc_param_slot_def (cfg, sp_offset, NULL); } /* if the function returns a struct on stack, the called method already does a ret $0x4 */ @@ -1541,6 +1669,8 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) } call->stack_usage = cinfo->stack_usage; + call->stack_align_amount = cinfo->stack_align_amount; + cfg->arch.param_area_size = MAX (cfg->arch.param_area_size, sp_offset); } void @@ -1790,6 +1920,27 @@ if (ins->inst_true_bb->native_offset) { \ static guint8* emit_call (MonoCompile *cfg, guint8 *code, guint32 patch_type, gconstpointer data) { + gboolean needs_paddings = TRUE; + guint32 pad_size; + MonoJumpInfo *jinfo = NULL; + + if (cfg->abs_patches) { + jinfo = g_hash_table_lookup (cfg->abs_patches, data); + if (jinfo && jinfo->type == MONO_PATCH_INFO_JIT_ICALL_ADDR) + needs_paddings = FALSE; + } + + if (cfg->compile_aot) + needs_paddings = FALSE; + /*The address must be 4 bytes aligned to avoid spanning multiple cache lines. + This is required for code patching to be safe on SMP machines. + */ + pad_size = (guint32)(code + 1 - cfg->native_code) & 0x3; +#ifndef __native_client_codegen__ + if (needs_paddings && pad_size) + x86_padding (code, 4 - pad_size); +#endif + mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data); x86_call_code (code, 0); @@ -2165,23 +2316,56 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code) return code; } +#ifdef __APPLE__ +static int tls_gs_offset; +#endif + gboolean mono_x86_have_tls_get (void) { #ifdef __APPLE__ - guint32 *ins = (guint32*)pthread_getspecific; + static gboolean have_tls_get = FALSE; + static gboolean inited = FALSE; + guint32 *ins; + + if (inited) + return have_tls_get; + + ins = (guint32*)pthread_getspecific; /* * We're looking for these two instructions: * * mov 0x4(%esp),%eax - * mov %gs:0x48(,%eax,4),%eax + * mov %gs:[offset](,%eax,4),%eax */ - return ins [0] == 0x0424448b && ins [1] == 0x85048b65 && ins [2] == 0x00000048; + have_tls_get = ins [0] == 0x0424448b && ins [1] == 0x85048b65; + tls_gs_offset = ins [2]; + + inited = TRUE; + + return have_tls_get; +#elif defined(TARGET_ANDROID) + return FALSE; #else return TRUE; #endif } +static guint8* +mono_x86_emit_tls_set (guint8* code, int sreg, int tls_offset) +{ +#if defined(__APPLE__) + x86_prefix (code, X86_GS_PREFIX); + x86_mov_mem_reg (code, tls_gs_offset + (tls_offset * 4), sreg, 4); +#elif defined(TARGET_WIN32) + g_assert_not_reached (); +#else + x86_prefix (code, X86_GS_PREFIX); + x86_mov_mem_reg (code, tls_offset, sreg, 4); +#endif + return code; +} + /* * mono_x86_emit_tls_get: * @code: buffer to store code to @@ -2199,7 +2383,7 @@ mono_x86_emit_tls_get (guint8* code, int dreg, int tls_offset) { #if defined(__APPLE__) x86_prefix (code, X86_GS_PREFIX); - x86_mov_reg_mem (code, dreg, 0x48 + tls_offset * 4, 4); + x86_mov_reg_mem (code, dreg, tls_gs_offset + (tls_offset * 4), 4); #elif defined(TARGET_WIN32) /* * See the Under the Hood article in the May 1996 issue of Microsoft Systems @@ -2243,7 +2427,7 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code) sig = mono_method_signature (method); - cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE); + cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig); /* This is the opposite of the code in emit_prolog */ @@ -2296,7 +2480,6 @@ x86_pop_reg (code, X86_EAX); #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting) #ifndef DISABLE_JIT - void mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) { @@ -2367,7 +2550,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) cfg->code_size *= 2; cfg->native_code = mono_realloc_native_code(cfg); code = cfg->native_code + offset; - mono_jit_stats.code_reallocs++; + cfg->stat_code_reallocs++; } if (cfg->debug_info) @@ -2578,6 +2761,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) */ for (i = 0; i < 6; ++i) x86_nop (code); + /* + * Add an additional nop so skipping the bp doesn't cause the ip to point + * to another IL offset. + */ + x86_nop (code); break; } case OP_ADDCC: @@ -2625,6 +2813,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_IDIV: case OP_IREM: +#if defined( __native_client_codegen__ ) + x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0); + EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "DivideByZeroException"); +#endif /* * The code is the same for div/rem, the allocator will allocate dreg * to RAX/RDX as appropriate. @@ -2642,6 +2834,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_IDIV_UN: case OP_IREM_UN: +#if defined( __native_client_codegen__ ) + x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0); + EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "DivideByZeroException"); +#endif if (ins->sreg2 == X86_EDX) { x86_push_reg (code, ins->sreg2); x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX); @@ -2653,6 +2849,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_DIV_IMM: +#if defined( __native_client_codegen__ ) + if (ins->inst_imm == 0) { + mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "DivideByZeroException"); + x86_jump32 (code, 0); + break; + } +#endif x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm); x86_cdq (code); x86_div_reg (code, ins->sreg2, TRUE); @@ -2989,6 +3192,56 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) cfg->disable_aot = TRUE; break; } + case OP_TAILCALL: { + MonoCallInst *call = (MonoCallInst*)ins; + int pos = 0, i; + + ins->flags |= MONO_INST_GC_CALLSITE; + ins->backend.pc_offset = code - cfg->native_code; + + /* FIXME: no tracing support... */ + if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) + code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE); + /* reset offset to make max_len work */ + offset = code - cfg->native_code; + + g_assert (!cfg->method->save_lmf); + + //code = emit_load_volatile_arguments (cfg, code); + + /* restore callee saved registers */ + for (i = 0; i < X86_NREG; ++i) + if (X86_IS_CALLEE_SAVED_REG (i) && cfg->used_int_regs & (1 << i)) + pos -= 4; + if (cfg->used_int_regs & (1 << X86_ESI)) { + x86_mov_reg_membase (code, X86_ESI, X86_EBP, pos, 4); + pos += 4; + } + if (cfg->used_int_regs & (1 << X86_EDI)) { + x86_mov_reg_membase (code, X86_EDI, X86_EBP, pos, 4); + pos += 4; + } + if (cfg->used_int_regs & (1 << X86_EBX)) { + x86_mov_reg_membase (code, X86_EBX, X86_EBP, pos, 4); + pos += 4; + } + + /* Copy arguments on the stack to our argument area */ + for (i = 0; i < call->stack_usage - call->stack_align_amount; i += 4) { + x86_mov_reg_membase (code, X86_EAX, X86_ESP, i, 4); + x86_mov_membase_reg (code, X86_EBP, 8 + i, X86_EAX, 4); + } + + /* restore ESP/EBP */ + x86_leave (code); + offset = code - cfg->native_code; + mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0); + x86_jump32 (code, 0); + + ins->flags |= MONO_INST_GC_CALLSITE; + cfg->disable_aot = TRUE; + break; + } case OP_CHECK_THIS: /* ensure ins->sreg1 is not NULL * note that cmp DWORD PTR [eax], eax is one byte shorter than @@ -3015,6 +3268,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method); else code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr); + ins->flags |= MONO_INST_GC_CALLSITE; + ins->backend.pc_offset = code - cfg->native_code; if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) { /* a pop is one byte, while an add reg, imm is 3. So if there are 4 or 8 * bytes to pop, we want to use pops. GCC does this (note it won't happen @@ -3047,6 +3302,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_CALL_REG: call = (MonoCallInst*)ins; x86_call_reg (code, ins->sreg1); + ins->flags |= MONO_INST_GC_CALLSITE; + ins->backend.pc_offset = code - cfg->native_code; if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) { if (call->stack_usage == 4) x86_pop_reg (code, X86_ECX); @@ -3064,6 +3321,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) call = (MonoCallInst*)ins; x86_call_membase (code, ins->sreg1, ins->inst_offset); + ins->flags |= MONO_INST_GC_CALLSITE; + ins->backend.pc_offset = code - cfg->native_code; if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) { if (call->stack_usage == 4) x86_pop_reg (code, X86_ECX); @@ -3137,6 +3396,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_push_reg (code, ins->sreg1); code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_arch_throw_exception"); + ins->flags |= MONO_INST_GC_CALLSITE; + ins->backend.pc_offset = code - cfg->native_code; break; } case OP_RETHROW: { @@ -3144,6 +3405,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_push_reg (code, ins->sreg1); code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_arch_rethrow_exception"); + ins->flags |= MONO_INST_GC_CALLSITE; + ins->backend.pc_offset = code - cfg->native_code; break; } case OP_CALL_HANDLER: @@ -3415,7 +3678,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) br = code; x86_branch8 (code, X86_CC_GEZ, 0, TRUE); /* add correction constant mn */ - x86_fld80_mem (code, mn); + if (cfg->compile_aot) { + x86_push_imm (code, (((guint32)mn [9]) << 24) | ((guint32)mn [8] << 16) | ((guint32)mn [7] << 8) | ((guint32)mn [6])); + x86_push_imm (code, (((guint32)mn [5]) << 24) | ((guint32)mn [4] << 16) | ((guint32)mn [3] << 8) | ((guint32)mn [2])); + x86_push_imm (code, (((guint32)mn [1]) << 24) | ((guint32)mn [0] << 16)); + x86_fld80_membase (code, X86_ESP, 2); + x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12); + } else { + x86_fld80_mem (code, mn); + } x86_fp_op_reg (code, X86_FADD, 1, TRUE); x86_patch (br, code); @@ -3595,8 +3866,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_fprem (code); x86_fnstsw (code); x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_C2); - l2 = code + 2; - x86_branch8 (code, X86_CC_NE, l1 - l2, FALSE); + l2 = code; + x86_branch8 (code, X86_CC_NE, 0, FALSE); + x86_patch (l2, l1); /* pop result */ x86_fstp (code, 1); @@ -3887,7 +4159,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; } case OP_MEMORY_BARRIER: { - /* Not needed on x86 */ + /* x86 only needs barrier for StoreLoad and FullBarrier */ + switch (ins->backend.memory_barrier_kind) { + case StoreLoadBarrier: + case FullBarrier: + /* http://blogs.sun.com/dave/resource/NHM-Pipeline-Blog-V2.txt */ + x86_prefix (code, X86_LOCK_PREFIX); + x86_alu_membase_imm (code, X86_ADD, X86_ESP, 0, 0); + break; + } break; } case OP_ATOMIC_ADD_I4: { @@ -4003,7 +4283,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_cmpxchg_membase_reg (code, ins->sreg1, ins->inst_offset, ins->sreg2); break; } -#ifdef HAVE_SGEN_GC case OP_CARD_TABLE_WBARRIER: { int ptr = ins->sreg1; int value = ins->sreg2; @@ -4013,6 +4292,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) size_t nursery_size; gulong card_table = (gulong)mono_gc_get_card_table (&card_table_shift, &card_table_mask); gulong nursery_start = (gulong)mono_gc_get_nursery (&nursery_shift, &nursery_size); + gboolean card_table_nursery_check = mono_gc_card_table_nursery_check (); /* * We need one register we can clobber, we choose EDX and make sreg1 @@ -4035,18 +4315,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) * done: */ - if (value != X86_EDX) - x86_mov_reg_reg (code, X86_EDX, value, 4); - x86_shift_reg_imm (code, X86_SHR, X86_EDX, nursery_shift); - x86_alu_reg_imm (code, X86_CMP, X86_EDX, nursery_start >> nursery_shift); - br = code; x86_branch8 (code, X86_CC_NE, -1, FALSE); + if (card_table_nursery_check) { + if (value != X86_EDX) + x86_mov_reg_reg (code, X86_EDX, value, 4); + x86_shift_reg_imm (code, X86_SHR, X86_EDX, nursery_shift); + x86_alu_reg_imm (code, X86_CMP, X86_EDX, nursery_start >> nursery_shift); + br = code; x86_branch8 (code, X86_CC_NE, -1, FALSE); + } x86_mov_reg_reg (code, X86_EDX, ptr, 4); x86_shift_reg_imm (code, X86_SHR, X86_EDX, card_table_shift); + if (card_table_mask) + x86_alu_reg_imm (code, X86_AND, X86_EDX, (int)card_table_mask); x86_mov_membase_imm (code, X86_EDX, card_table, 1, 1); - x86_patch (br, code); + if (card_table_nursery_check) + x86_patch (br, code); break; } -#endif #ifdef MONO_ARCH_SIMD_INTRINSICS case OP_ADDPS: x86_sse_alu_ps_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2); @@ -4119,6 +4403,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF); x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->sreg1, ins->inst_c0); break; + case OP_SHUFPS: + g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF); + x86_sse_alu_reg_reg_imm8 (code, X86_SSE_SHUFP, ins->sreg1, ins->sreg2, ins->inst_c0); + break; + case OP_SHUFPD: + g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0x3); + x86_sse_alu_pd_reg_reg_imm8 (code, X86_SSE_SHUFP, ins->sreg1, ins->sreg2, ins->inst_c0); + break; case OP_ADDPD: x86_sse_alu_pd_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2); @@ -4498,10 +4790,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_INSERTX_R8_SLOW: x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE); + if (cfg->verbose_level) + printf ("CONVERTING a OP_INSERTX_R8_SLOW %d offset %x\n", ins->inst_c0, offset); if (ins->inst_c0) x86_sse_alu_pd_reg_membase (code, X86_SSE_MOVHPD_REG_MEMBASE, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset); else - x86_sse_alu_pd_reg_membase (code, X86_SSE_MOVSD_REG_MEMBASE, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset); + x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset); break; case OP_STOREX_MEMBASE_REG: @@ -4587,6 +4881,32 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset); x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0x44); break; + + case OP_CVTDQ2PD: + x86_sse_alu_ss_reg_reg (code, X86_SSE_CVTDQ2PD, ins->dreg, ins->sreg1); + break; + case OP_CVTDQ2PS: + x86_sse_alu_ps_reg_reg (code, X86_SSE_CVTDQ2PS, ins->dreg, ins->sreg1); + break; + case OP_CVTPD2DQ: + x86_sse_alu_sd_reg_reg (code, X86_SSE_CVTPD2DQ, ins->dreg, ins->sreg1); + break; + case OP_CVTPD2PS: + x86_sse_alu_pd_reg_reg (code, X86_SSE_CVTPD2PS, ins->dreg, ins->sreg1); + break; + case OP_CVTPS2DQ: + x86_sse_alu_pd_reg_reg (code, X86_SSE_CVTPS2DQ, ins->dreg, ins->sreg1); + break; + case OP_CVTPS2PD: + x86_sse_alu_ps_reg_reg (code, X86_SSE_CVTPS2PD, ins->dreg, ins->sreg1); + break; + case OP_CVTTPD2DQ: + x86_sse_alu_pd_reg_reg (code, X86_SSE_CVTTPD2DQ, ins->dreg, ins->sreg1); + break; + case OP_CVTTPS2DQ: + x86_sse_alu_ss_reg_reg (code, X86_SSE_CVTTPS2DQ, ins->dreg, ins->sreg1); + break; + #endif case OP_LIVERANGE_START: { if (cfg->verbose_level > 1) @@ -4600,6 +4920,30 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code; break; } + case OP_NACL_GC_SAFE_POINT: { +#if defined(__native_client_codegen__) && defined(__native_client_gc__) + if (cfg->compile_aot) + code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)mono_nacl_gc); + else { + guint8 *br [1]; + + x86_test_mem_imm8 (code, (gpointer)&__nacl_thread_suspension_needed, 0xFFFFFFFF); + br[0] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE); + code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)mono_nacl_gc); + x86_patch (br[0], code); + } +#endif + break; + } + case OP_GC_LIVENESS_DEF: + case OP_GC_LIVENESS_USE: + case OP_GC_PARAM_SLOT_LIVENESS_DEF: + ins->backend.pc_offset = code - cfg->native_code; + break; + case OP_GC_SPILL_SLOT_LIVENESS_DEF: + ins->backend.pc_offset = code - cfg->native_code; + bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins); + break; default: g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode)); g_assert_not_reached (); @@ -4627,7 +4971,7 @@ mono_arch_register_lowlevel_calls (void) } void -mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors) +mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors) { MonoJumpInfo *patch_info; gboolean compile_aot = !run_cctors; @@ -4670,19 +5014,60 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono case MONO_PATCH_INFO_GENERIC_CLASS_INIT: case MONO_PATCH_INFO_MONITOR_ENTER: case MONO_PATCH_INFO_MONITOR_EXIT: + case MONO_PATCH_INFO_JIT_ICALL_ADDR: +#if defined(__native_client_codegen__) && defined(__native_client__) + if (nacl_is_code_address (code)) { + /* For tail calls, code is patched after being installed */ + /* but not through the normal "patch callsite" method. */ + unsigned char buf[kNaClAlignment]; + unsigned char *aligned_code = (uintptr_t)code & ~kNaClAlignmentMask; + unsigned char *_target = target; + int ret; + /* All patch targets modified in x86_patch */ + /* are IP relative. */ + _target = _target + (uintptr_t)buf - (uintptr_t)aligned_code; + memcpy (buf, aligned_code, kNaClAlignment); + /* Patch a temp buffer of bundle size, */ + /* then install to actual location. */ + x86_patch (buf + ((uintptr_t)code - (uintptr_t)aligned_code), _target); + ret = nacl_dyncode_modify (aligned_code, buf, kNaClAlignment); + g_assert (ret == 0); + } + else { + x86_patch (ip, target); + } +#else x86_patch (ip, target); +#endif break; case MONO_PATCH_INFO_NONE: break; + case MONO_PATCH_INFO_R4: + case MONO_PATCH_INFO_R8: { + guint32 offset = mono_arch_get_patch_offset (ip); + *((gconstpointer *)(ip + offset)) = target; + break; + } default: { guint32 offset = mono_arch_get_patch_offset (ip); +#if !defined(__native_client__) *((gconstpointer *)(ip + offset)) = target; +#else + *((gconstpointer *)(ip + offset)) = nacl_modify_patch_target (target); +#endif break; } } } } +static G_GNUC_UNUSED void +stack_unaligned (MonoMethod *m, gpointer caller) +{ + printf ("%s\n", mono_method_full_name (m, TRUE)); + g_assert_not_reached (); +} + guint8 * mono_arch_emit_prolog (MonoCompile *cfg) { @@ -4702,8 +5087,11 @@ mono_arch_emit_prolog (MonoCompile *cfg) if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) cfg->code_size += 512; -#ifdef __native_client_codegen__ +#if defined(__default_codegen__) + code = cfg->native_code = g_malloc (cfg->code_size); +#elif defined(__native_client_codegen__) /* native_code_alloc is not 32-byte aligned, native_code is. */ + cfg->code_size = NACL_BUNDLE_ALIGN_UP (cfg->code_size); cfg->native_code_alloc = g_malloc (cfg->code_size + kNaClAlignment); /* Align native_code to next nearest kNaclAlignment byte. */ @@ -4714,8 +5102,24 @@ mono_arch_emit_prolog (MonoCompile *cfg) alignment_check = (guint)cfg->native_code & kNaClAlignmentMask; g_assert(alignment_check == 0); -#else - code = cfg->native_code = g_malloc (cfg->code_size); +#endif + +#if 0 + { + guint8 *br [16]; + + /* Check that the stack is aligned on osx */ + x86_mov_reg_reg (code, X86_EAX, X86_ESP, sizeof (mgreg_t)); + x86_alu_reg_imm (code, X86_AND, X86_EAX, 15); + x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0xc); + br [0] = code; + x86_branch_disp (code, X86_CC_Z, 0, FALSE); + x86_push_membase (code, X86_ESP, 0); + x86_push_imm (code, cfg->method); + x86_mov_reg_imm (code, X86_EAX, stack_unaligned); + x86_call_reg (code, X86_EAX); + x86_patch (br [0], code); + } #endif /* Offset between RSP and the CFA */ @@ -4727,6 +5131,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) // IP saved at CFA - 4 /* There is no IP reg on x86 */ mono_emit_unwind_op_offset (cfg, code, X86_NREG, -cfa_offset); + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF); need_stack_frame = needs_stack_frame (cfg); @@ -4737,54 +5142,15 @@ mono_arch_emit_prolog (MonoCompile *cfg) mono_emit_unwind_op_offset (cfg, code, X86_EBP, - cfa_offset); x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4); mono_emit_unwind_op_def_cfa_reg (cfg, code, X86_EBP); + /* These are handled automatically by the stack marking code */ + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF); + } else { + cfg->frame_reg = X86_ESP; } alloc_size = cfg->stack_offset; pos = 0; - if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) { - /* 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 = mono_x86_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 = mono_x86_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); - x86_patch (buf, code); -#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)); -#endif - } - else { - if (cfg->compile_aot) { - /* - * This goes before the saving of callee saved regs, so save the got reg - * ourselves. - */ - x86_push_reg (code, MONO_ARCH_GOT_REG); - code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL); - x86_push_imm (code, 0); - } else { - 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); - if (cfg->compile_aot) - x86_pop_reg (code, MONO_ARCH_GOT_REG); - } - } - if (method->save_lmf) { pos += sizeof (MonoLMF); @@ -4797,19 +5163,24 @@ mono_arch_emit_prolog (MonoCompile *cfg) x86_push_imm_template (code); } cfa_offset += sizeof (gpointer); + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF); /* save all caller saved regs */ x86_push_reg (code, X86_EBP); cfa_offset += sizeof (gpointer); + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF); x86_push_reg (code, X86_ESI); cfa_offset += sizeof (gpointer); mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset); + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF); x86_push_reg (code, X86_EDI); cfa_offset += sizeof (gpointer); mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset); + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF); x86_push_reg (code, X86_EBX); cfa_offset += sizeof (gpointer); mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset); + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF); if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) { /* @@ -4817,15 +5188,19 @@ mono_arch_emit_prolog (MonoCompile *cfg) * through the mono_lmf_addr TLS variable. */ /* %eax = previous_lmf */ - x86_prefix (code, X86_GS_PREFIX); - x86_mov_reg_mem (code, X86_EAX, lmf_tls_offset, 4); + code = mono_x86_emit_tls_get (code, X86_EAX, lmf_tls_offset); /* skip esp + method_info + lmf */ x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12); + cfa_offset += 12; + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF); + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + 4, SLOT_NOREF); + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + 8, SLOT_NOREF); /* push previous_lmf */ x86_push_reg (code, X86_EAX); + cfa_offset += 4; + mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF); /* new lmf = ESP */ - x86_prefix (code, X86_GS_PREFIX); - x86_mov_mem_reg (code, lmf_tls_offset, X86_ESP, 4); + code = mono_x86_emit_tls_set (code, X86_ESP, lmf_tls_offset); } else { /* get the address of lmf for the current thread */ /* @@ -4864,6 +5239,8 @@ mono_arch_emit_prolog (MonoCompile *cfg) pos += 4; cfa_offset += sizeof (gpointer); mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset); + /* These are handled automatically by the stack marking code */ + mini_gc_set_slot_type_from_cfa (cfg, - cfa_offset, SLOT_NOREF); } if (cfg->used_int_regs & (1 << X86_EDI)) { @@ -4871,6 +5248,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) pos += 4; cfa_offset += sizeof (gpointer); mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset); + mini_gc_set_slot_type_from_cfa (cfg, - cfa_offset, SLOT_NOREF); } if (cfg->used_int_regs & (1 << X86_ESI)) { @@ -4878,6 +5256,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) pos += 4; cfa_offset += sizeof (gpointer); mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset); + mini_gc_set_slot_type_from_cfa (cfg, - cfa_offset, SLOT_NOREF); } } @@ -4889,10 +5268,15 @@ mono_arch_emit_prolog (MonoCompile *cfg) if (need_stack_frame) tot += 4; /* ebp */ tot &= MONO_ARCH_FRAME_ALIGNMENT - 1; - if (tot) + if (tot) { alloc_size += MONO_ARCH_FRAME_ALIGNMENT - tot; + for (i = 0; i < MONO_ARCH_FRAME_ALIGNMENT - tot; i += sizeof (mgreg_t)) + mini_gc_set_slot_type_from_fp (cfg, - (alloc_size + pos - i), SLOT_NOREF); + } } + cfg->arch.sp_fp_offset = alloc_size + pos; + if (alloc_size) { /* See mono_emit_stack_alloc */ #if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK) @@ -4905,7 +5289,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) cfg->code_size *= 2; cfg->native_code = mono_realloc_native_code(cfg); code = cfg->native_code + offset; - mono_jit_stats.code_reallocs++; + cfg->stat_code_reallocs++; } while (remaining_size >= 0x1000) { x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000); @@ -4951,19 +5335,38 @@ mono_arch_emit_prolog (MonoCompile *cfg) max_offset += LOOP_ALIGNMENT; #ifdef __native_client_codegen__ /* max alignment for native client */ - max_offset += kNaClAlignment; + if (bb->flags & BB_INDIRECT_JUMP_TARGET || bb->flags & BB_EXCEPTION_HANDLER) + max_offset += kNaClAlignment; #endif MONO_BB_FOR_EACH_INS (bb, ins) { if (ins->opcode == OP_LABEL) ins->inst_c1 = max_offset; #ifdef __native_client_codegen__ + switch (ins->opcode) { - int space_in_block = kNaClAlignment - - ((max_offset + cfg->code_len) & kNaClAlignmentMask); - int max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; - if (space_in_block < max_len && max_len < kNaClAlignment) { - max_offset += space_in_block; - } + case OP_FCALL: + case OP_LCALL: + case OP_VCALL: + case OP_VCALL2: + case OP_VOIDCALL: + case OP_CALL: + case OP_FCALL_REG: + case OP_LCALL_REG: + case OP_VCALL_REG: + case OP_VCALL2_REG: + case OP_VOIDCALL_REG: + case OP_CALL_REG: + case OP_FCALL_MEMBASE: + case OP_LCALL_MEMBASE: + case OP_VCALL_MEMBASE: + case OP_VCALL2_MEMBASE: + case OP_VOIDCALL_MEMBASE: + case OP_CALL_MEMBASE: + max_offset += kNaClAlignment; + break; + default: + max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN] - 1; + break; } #endif /* __native_client_codegen__ */ max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; @@ -5021,7 +5424,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) { cfg->code_size *= 2; cfg->native_code = mono_realloc_native_code(cfg); - mono_jit_stats.code_reallocs++; + cfg->stat_code_reallocs++; } code = cfg->native_code + cfg->code_len; @@ -5062,8 +5465,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4); /* lmf = previous_lmf */ - x86_prefix (code, X86_GS_PREFIX); - x86_mov_mem_reg (code, lmf_tls_offset, X86_ECX, 4); + code = mono_x86_emit_tls_set (code, X86_ECX, lmf_tls_offset); } else { /* Find a spare register */ switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) { @@ -5128,7 +5530,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) } /* Load returned vtypes into registers if needed */ - cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE); + cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig); if (cinfo->ret.storage == ArgValuetypeInReg) { for (quad = 0; quad < 2; quad ++) { switch (cinfo->ret.pair_storage [quad]) { @@ -5155,8 +5557,8 @@ mono_arch_emit_epilog (MonoCompile *cfg) if (CALLCONV_IS_STDCALL (sig)) { MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1)); - stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info); - } else if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret) && (cinfo->ret.storage == ArgOnStack)) + stack_to_pop = mono_arch_get_argument_info (NULL, sig, sig->param_count, arg_info); + } else if (cinfo->vtype_retaddr) stack_to_pop = 4; else stack_to_pop = 0; @@ -5202,7 +5604,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg) while (cfg->code_len + code_size > (cfg->code_size - 16)) { cfg->code_size *= 2; cfg->native_code = mono_realloc_native_code(cfg); - mono_jit_stats.code_reallocs++; + cfg->stat_code_reallocs++; } code = cfg->native_code + cfg->code_len; @@ -5234,11 +5636,11 @@ mono_arch_emit_exceptions (MonoCompile *cfg) guint32 size; /* Compute size of code following the push */ -#ifdef __native_client_codegen__ +#if defined(__default_codegen__) + size = 5 + 5; +#elif defined(__native_client_codegen__) code = mono_nacl_align (code); size = kNaClAlignment; -#else - size = 5 + 5; #endif /*This is aligned to 16 bytes by the callee. This way we save a few bytes here.*/ @@ -5302,41 +5704,31 @@ mono_arch_is_inst_imm (gint64 imm) return TRUE; } -/* - * Support for fast access to the thread-local lmf structure using the GS - * segment register on NPTL + kernel 2.6.x. - */ - -static gboolean tls_offset_inited = FALSE; - void -mono_arch_setup_jit_tls_data (MonoJitTlsData *tls) +mono_arch_finish_init (void) { - if (!tls_offset_inited) { - if (!getenv ("MONO_NO_TLS")) { + if (!getenv ("MONO_NO_TLS")) { #ifdef TARGET_WIN32 - /* - * We need to init this multiple times, since when we are first called, the key might not - * be initialized yet. - */ - appdomain_tls_offset = mono_domain_get_tls_key (); - lmf_tls_offset = mono_get_jit_tls_key (); - - /* Only 64 tls entries can be accessed using inline code */ - if (appdomain_tls_offset >= 64) - appdomain_tls_offset = -1; - if (lmf_tls_offset >= 64) - lmf_tls_offset = -1; + /* + * We need to init this multiple times, since when we are first called, the key might not + * be initialized yet. + */ + appdomain_tls_offset = mono_domain_get_tls_key (); + lmf_tls_offset = mono_get_jit_tls_key (); + + /* Only 64 tls entries can be accessed using inline code */ + if (appdomain_tls_offset >= 64) + appdomain_tls_offset = -1; + if (lmf_tls_offset >= 64) + lmf_tls_offset = -1; #else #if MONO_XEN_OPT - optimize_for_xen = access ("/proc/xen", F_OK) == 0; + optimize_for_xen = access ("/proc/xen", F_OK) == 0; #endif - tls_offset_inited = TRUE; - appdomain_tls_offset = mono_domain_get_tls_offset (); - lmf_tls_offset = mono_get_lmf_tls_offset (); - lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset (); + appdomain_tls_offset = mono_domain_get_tls_offset (); + lmf_tls_offset = mono_get_lmf_tls_offset (); + lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset (); #endif - } } } @@ -5354,16 +5746,15 @@ mono_arch_free_jit_tls_data (MonoJitTlsData *tls) //[1 + 5] x86_jump_mem(inst,mem) #define CMP_SIZE 6 -#ifdef __native_client_codegen__ -/* These constants should be coming from cpu-x86.md */ +#if defined(__default_codegen__) +#define BR_SMALL_SIZE 2 +#define BR_LARGE_SIZE 5 +#elif defined(__native_client_codegen__) /* I suspect the size calculation below is actually incorrect. */ -/* TODO: fix the calculation that uses these sizes. */ +/* TODO: fix the calculation that uses these sizes. */ #define BR_SMALL_SIZE 16 #define BR_LARGE_SIZE 12 -#else -#define BR_SMALL_SIZE 2 -#define BR_LARGE_SIZE 5 -#endif /* __native_client_codegen__ */ +#endif /*__native_client_codegen__*/ #define JUMP_IMM_SIZE 6 #define ENABLE_WRONG_METHOD_CHECK 0 #define DEBUG_IMT 0 @@ -5388,9 +5779,6 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI int size = 0; guint8 *code, *start; -#ifdef __native_client_codegen__ - /* g_print("mono_arch_build_imt_thunk needs to be aligned.\n"); */ -#endif for (i = 0; i < count; ++i) { MonoIMTCheckItem *item = imt_entries [i]; if (item->is_equals) { @@ -5414,10 +5802,17 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI } size += item->chunk_size; } +#if defined(__native_client__) && defined(__native_client_codegen__) + /* In Native Client, we don't re-use thunks, allocate from the */ + /* normal code manager paths. */ + size = NACL_BUNDLE_ALIGN_UP (size); + code = mono_domain_code_reserve (domain, size); +#else if (fail_tramp) code = mono_method_alloc_generic_virtual_thunk (domain, size); else code = mono_domain_code_reserve (domain, size); +#endif start = code; for (i = 0; i < count; ++i) { MonoIMTCheckItem *item = imt_entries [i]; @@ -5492,6 +5887,17 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI g_free (buff); } #endif + if (mono_jit_map_is_enabled ()) { + char *buff; + if (vtable) + buff = g_strdup_printf ("imt_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count); + else + buff = g_strdup_printf ("imt_thunk_entries_%d", count); + mono_emit_jit_tramp (start, code - start, buff); + g_free (buff); + } + + nacl_domain_code_validate (domain, &start, size, &code); return start; } @@ -5610,9 +6016,9 @@ mono_arch_get_patch_offset (guint8 *code) { if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2)) return 2; - else if ((code [0] == 0xba)) + else if (code [0] == 0xba) return 1; - else if ((code [0] == 0x68)) + else if (code [0] == 0x68) /* push IMM */ return 1; else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6)) @@ -5695,8 +6101,7 @@ mono_x86_get_this_arg_offset (MonoGenericSharingContext *gsctx, MonoMethodSignat } gpointer -mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, - mgreg_t *regs, guint8 *code) +mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code) { guint32 esp = regs [X86_ESP]; CallInfo *cinfo = NULL; @@ -5724,6 +6129,7 @@ static gpointer get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len) { guint8 *code, *start; + int code_reserve = 64; /* * The stack contains: @@ -5732,7 +6138,7 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod */ if (has_target) { - start = code = mono_global_codeman_reserve (64); + start = code = mono_global_codeman_reserve (code_reserve); /* Replace the this argument with the target */ x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); @@ -5740,15 +6146,15 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4); x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr)); - g_assert ((code - start) < 64); + g_assert ((code - start) < code_reserve); } else { int i = 0; /* 8 for mov_reg and jump, plus 8 for each parameter */ #ifdef __native_client_codegen__ /* TODO: calculate this size correctly */ - int code_reserve = 13 + (param_count * 8) + 2 * kNaClAlignment; + code_reserve = 13 + (param_count * 8) + 2 * kNaClAlignment; #else - int code_reserve = 8 + (param_count * 8); + code_reserve = 8 + (param_count * 8); #endif /* __native_client_codegen__ */ /* * The stack contains: @@ -5782,11 +6188,23 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod g_assert ((code - start) < code_reserve); } + nacl_global_codeman_validate(&start, code_reserve, &code); mono_debug_add_delegate_trampoline (start, code - start); if (code_len) *code_len = code - start; + if (mono_jit_map_is_enabled ()) { + char *buff; + if (has_target) + buff = (char*)"delegate_invoke_has_target"; + else + buff = g_strdup_printf ("delegate_invoke_no_target_%d", param_count); + mono_emit_jit_tramp (start, code - start, buff); + if (!has_target) + g_free (buff); + } + return start; } @@ -5868,19 +6286,54 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe return start; } -gpointer +mgreg_t mono_arch_context_get_int_reg (MonoContext *ctx, int reg) { switch (reg) { - case X86_EAX: return (gpointer)ctx->eax; - case X86_EBX: return (gpointer)ctx->ebx; - case X86_ECX: return (gpointer)ctx->ecx; - case X86_EDX: return (gpointer)ctx->edx; - case X86_ESP: return (gpointer)ctx->esp; - case X86_EBP: return (gpointer)ctx->ebp; - case X86_ESI: return (gpointer)ctx->esi; - case X86_EDI: return (gpointer)ctx->edi; - default: g_assert_not_reached (); + case X86_EAX: return ctx->eax; + case X86_EBX: return ctx->ebx; + case X86_ECX: return ctx->ecx; + case X86_EDX: return ctx->edx; + case X86_ESP: return ctx->esp; + case X86_EBP: return ctx->ebp; + case X86_ESI: return ctx->esi; + case X86_EDI: return ctx->edi; + default: + g_assert_not_reached (); + return 0; + } +} + +void +mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val) +{ + switch (reg) { + case X86_EAX: + ctx->eax = val; + break; + case X86_EBX: + ctx->ebx = val; + break; + case X86_ECX: + ctx->ecx = val; + break; + case X86_EDX: + ctx->edx = val; + break; + case X86_ESP: + ctx->esp = val; + break; + case X86_EBP: + ctx->ebp = val; + break; + case X86_ESI: + ctx->esi = val; + break; + case X86_EDI: + ctx->edi = val; + break; + default: + g_assert_not_reached (); } } @@ -6232,7 +6685,8 @@ gboolean 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 */ + EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; /* 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 @@ -6251,7 +6705,7 @@ gboolean 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 */ + EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; /* 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 @@ -6266,44 +6720,15 @@ mono_arch_is_breakpoint_event (void *info, void *sigctx) #endif } -/* - * mono_arch_get_ip_for_breakpoint: - * - * See mini-amd64.c for docs. - */ -guint8* -mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx) -{ - guint8 *ip = MONO_CONTEXT_GET_IP (ctx); - - return ip; -} - #define BREAKPOINT_SIZE 6 -/* - * mono_arch_get_ip_for_single_step: - * - * See mini-amd64.c for docs. - */ -guint8* -mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx) -{ - guint8 *ip = MONO_CONTEXT_GET_IP (ctx); - - /* Size of x86_alu_reg_imm */ - ip += 6; - - return ip; -} - /* * mono_arch_skip_breakpoint: * * See mini-amd64.c for docs. */ void -mono_arch_skip_breakpoint (MonoContext *ctx) +mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji) { MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE); } @@ -6333,3 +6758,8 @@ mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code) #endif +#if defined(MONOTOUCH) || defined(MONO_EXTENSIONS) + +#include "../../../mono-extensions/mono/mini/mini-x86-gsharedvt.c" + +#endif /* !MONOTOUCH */