X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini.c;h=45d34347c47070d0b31b194c60f83633eb6e9775;hb=557c65a64b6c108f4c42bbabf00f7f2d07b2c2b7;hp=319b6945ed650793b22e10c5598ed644321ac9b9;hpb=f8a1d28e8de7da6fdafee6223906a4a9aba811cd;p=mono.git diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 319b6945ed6..45d34347c47 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -6,7 +6,7 @@ * Dietmar Maurer (dietmar@ximian.com) * * Copyright 2002-2003 Ximian, Inc. - * Coprygith 2003-2010 Novell, Inc. + * Copyright 2003-2010 Novell, Inc. */ #define MONO_LLVM_IN_MINI 1 @@ -69,38 +69,18 @@ #include "mini-gc.h" #include "debugger-agent.h" -#if defined(HAVE_KW_THREAD) -#define MINI_FAST_TLS_SET(x,y) x = y -#define MINI_FAST_TLS_GET(x) x -#define MINI_FAST_TLS_INIT(x) -#define MINI_FAST_TLS_DECLARE(x) static __thread gpointer x MONO_TLS_FAST; -#define MINI_HAVE_FAST_TLS -#define MINI_THREAD_VAR_OFFSET(x,y) MONO_THREAD_VAR_OFFSET(x,y) -#elif (defined(__APPLE__) && defined(__i386__)) -#define MINI_FAST_TLS_SET(x,y) pthread_setspecific(x, y) -#define MINI_FAST_TLS_GET(x) pthread_getspecific(x) -#define MINI_FAST_TLS_INIT(x) pthread_key_create(&x, NULL) -#define MINI_FAST_TLS_DECLARE(x) static pthread_key_t x; -#define MINI_HAVE_FAST_TLS -#define MINI_THREAD_VAR_OFFSET(x,y) y = (gint32) x -#else -#define MINI_THREAD_VAR_OFFSET(x,y) MONO_THREAD_VAR_OFFSET(x,y) -#endif - static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex); -#ifdef __native_client_codegen__ -/* Default alignment for Native Client is 32-byte. */ -guint8 nacl_align_byte = 0xe0; -#endif static guint32 default_opt = 0; static gboolean default_opt_set = FALSE; guint32 mono_jit_tls_id = -1; -#ifdef MINI_HAVE_FAST_TLS -MINI_FAST_TLS_DECLARE(mono_jit_tls); +MONO_FAST_TLS_DECLARE(mono_jit_tls); + +#ifndef MONO_ARCH_MONITOR_ENTER_ADJUSTMENT +#define MONO_ARCH_MONITOR_ENTER_ADJUSTMENT 1 #endif MonoTraceSpec *mono_jit_trace_calls = NULL; @@ -160,6 +140,38 @@ gboolean disable_vtypes_in_regs = FALSE; gboolean mono_dont_free_global_codeman; +gpointer +mono_realloc_native_code (MonoCompile *cfg) +{ +#if defined(__default_codegen__) + return g_realloc (cfg->native_code, cfg->code_size); +#elif defined(__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 + g_assert_not_reached (); + return cfg->native_code; +#endif +} + #ifdef __native_client_codegen__ /* Prevent instructions from straddling a 32-byte alignment boundary. */ @@ -336,6 +348,10 @@ mono_pmip (void *ip) * output. Unlike mono_pmip which returns a string, this routine * prints the value on the standard output. */ +#ifdef __GNUC__ +/* Prevent the linker from optimizing this away in embedding setups to help debugging */ + __attribute__((used)) +#endif void mono_print_method_from_ip (void *ip) { @@ -360,6 +376,7 @@ mono_print_method_from_ip (void *ip) } else g_print ("No method at %p\n", ip); + fflush (stdout); return; } method = mono_method_full_name (ji->method, TRUE); @@ -369,6 +386,7 @@ mono_print_method_from_ip (void *ip) if (source) g_print ("%s:%d\n", source->source_file, source->row); + fflush (stdout); mono_debug_free_source_location (source); g_free (method); @@ -426,6 +444,67 @@ void *mono_global_codeman_reserve (int size) } } +#if defined(__native_client_codegen__) && defined(__native_client__) +/* Given the temporary buffer (allocated by mono_global_codeman_reserve) into + * which we are generating code, return a pointer to the destination in the + * dynamic code segment into which the code will be copied when + * mono_global_codeman_commit is called. + * LOCKING: Acquires the jit lock. + */ +void* +nacl_global_codeman_get_dest (void *data) +{ + void *dest; + mono_jit_lock (); + dest = nacl_code_manager_get_code_dest (global_codeman, data); + mono_jit_unlock (); + return dest; +} + +void +mono_global_codeman_commit (void *data, int size, int newsize) +{ + mono_jit_lock (); + mono_code_manager_commit (global_codeman, data, size, newsize); + mono_jit_unlock (); +} + +/* + * Convenience function which calls mono_global_codeman_commit to validate and + * copy the code. The caller sets *buf_base and *buf_size to the start and size + * of the buffer (allocated by mono_global_codeman_reserve), and *code_end to + * the byte after the last instruction byte. On return, *buf_base will point to + * the start of the copied in the code segment, and *code_end will point after + * the end of the copied code. + */ +void +nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end) +{ + guint8 *tmp = nacl_global_codeman_get_dest (*buf_base); + mono_global_codeman_commit (*buf_base, buf_size, *code_end - *buf_base); + *code_end = tmp + (*code_end - *buf_base); + *buf_base = tmp; +} +#else +/* no-op versions of Native Client functions */ +void* +nacl_global_codeman_get_dest (void *data) +{ + return data; +} + +void +mono_global_codeman_commit (void *data, int size, int newsize) +{ +} + +void +nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end) +{ +} + +#endif /* __native_client__ */ + /** * mono_create_unwind_op: * @@ -1040,8 +1119,15 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, inst->dreg = vreg; if (cfg->compute_gc_maps) { - if ((MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->klass->has_references) || MONO_TYPE_IS_REFERENCE (inst->inst_vtype)) - inst->flags |= MONO_INST_GC_TRACK; + if (type->byref) { + mono_mark_vreg_as_mp (cfg, vreg); + } else { + MonoType *t = mini_type_get_underlying_type (NULL, type); + if ((MONO_TYPE_ISSTRUCT (t) && inst->klass->has_references) || mini_type_is_reference (cfg, t)) { + inst->flags |= MONO_INST_GC_TRACK; + mono_mark_vreg_as_ref (cfg, vreg); + } + } } cfg->varinfo [num] = inst; @@ -1148,6 +1234,38 @@ mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) #endif +void +mono_mark_vreg_as_ref (MonoCompile *cfg, int vreg) +{ + if (vreg >= cfg->vreg_is_ref_len) { + gboolean *tmp = cfg->vreg_is_ref; + int size = cfg->vreg_is_ref_len; + + while (vreg >= cfg->vreg_is_ref_len) + cfg->vreg_is_ref_len = cfg->vreg_is_ref_len ? cfg->vreg_is_ref_len * 2 : 32; + cfg->vreg_is_ref = mono_mempool_alloc0 (cfg->mempool, sizeof (gboolean) * cfg->vreg_is_ref_len); + if (size) + memcpy (cfg->vreg_is_ref, tmp, size * sizeof (gboolean)); + } + cfg->vreg_is_ref [vreg] = TRUE; +} + +void +mono_mark_vreg_as_mp (MonoCompile *cfg, int vreg) +{ + if (vreg >= cfg->vreg_is_mp_len) { + gboolean *tmp = cfg->vreg_is_mp; + int size = cfg->vreg_is_mp_len; + + while (vreg >= cfg->vreg_is_mp_len) + cfg->vreg_is_mp_len = cfg->vreg_is_mp_len ? cfg->vreg_is_mp_len * 2 : 32; + cfg->vreg_is_mp = mono_mempool_alloc0 (cfg->mempool, sizeof (gboolean) * cfg->vreg_is_mp_len); + if (size) + memcpy (cfg->vreg_is_mp, tmp, size * sizeof (gboolean)); + } + cfg->vreg_is_mp [vreg] = TRUE; +} + static MonoType* type_from_stack_type (MonoInst *ins) { switch (ins->type) { @@ -1371,12 +1489,13 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile) if (method->verification_success) return FALSE; - is_fulltrust = mono_verifier_is_method_full_trust (method); - if (!mono_verifier_is_enabled_for_method (method)) return FALSE; - res = mono_method_verify_with_current_settings (method, cfg->skip_visibility); + /*skip verification implies the assembly must be */ + is_fulltrust = mono_verifier_is_method_full_trust (method) || mini_assembly_can_skip_verification (cfg->domain, method); + + res = mono_method_verify_with_current_settings (method, cfg->skip_visibility, is_fulltrust); if ((error = mono_loader_get_last_error ())) { if (fail_compile) @@ -1423,8 +1542,7 @@ gboolean mono_compile_is_broken (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile) { MonoMethod *method_definition = method; - gboolean dont_verify = mini_assembly_can_skip_verification (cfg->domain, method); - dont_verify |= method->klass->image->assembly->corlib_internal; + gboolean dont_verify = method->klass->image->assembly->corlib_internal; while (method_definition->is_inflated) { MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition; @@ -1537,7 +1655,7 @@ compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b) #endif static gint32* -mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align) +mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align) { int i, slot, offset, size; guint32 align; @@ -1641,7 +1759,7 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s case MONO_TYPE_PTR: case MONO_TYPE_I: case MONO_TYPE_U: -#if SIZEOF_REGISTER == 4 +#if SIZEOF_VOID_P == 4 case MONO_TYPE_I4: #else case MONO_TYPE_I8: @@ -1780,6 +1898,12 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s LSCAN_DEBUG (printf ("R%d %s -> 0x%x\n", inst->dreg, mono_type_full_name (t), slot)); + if (inst->flags & MONO_INST_LMF) { + size = sizeof (MonoLMF); + align = sizeof (mgreg_t); + reuse_slot = FALSE; + } + if (!reuse_slot) slot = 0xffffff; @@ -1830,7 +1954,7 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s } /* - * mono_allocate_stack_slots_full: + * mono_allocate_stack_slots: * * Allocate stack slots for all non register allocated variables using a * linear scan algorithm. @@ -1839,7 +1963,7 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s * STACK_ALIGN is set to the alignment needed by the locals area. */ gint32* -mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align) +mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align) { int i, slot, offset, size; guint32 align; @@ -1853,7 +1977,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st gboolean reuse_slot; if ((cfg->num_varinfo > 0) && MONO_VARINFO (cfg, 0)->interval) - return mono_allocate_stack_slots_full2 (cfg, backward, stack_size, stack_align); + return mono_allocate_stack_slots2 (cfg, backward, stack_size, stack_align); scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED); vtype_stack_slots = NULL; @@ -1875,7 +1999,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st vars = mono_varlist_sort (cfg, vars, 0); offset = 0; - *stack_align = sizeof (gpointer); + *stack_align = sizeof(mgreg_t); for (l = vars; l; l = l->next) { vmv = l->data; inst = cfg->varinfo [vmv->idx]; @@ -1930,7 +2054,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st case MONO_TYPE_PTR: case MONO_TYPE_I: case MONO_TYPE_U: -#if SIZEOF_REGISTER == 4 +#if SIZEOF_VOID_P == 4 case MONO_TYPE_I4: #else case MONO_TYPE_I8: @@ -2008,6 +2132,16 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st */ } + if (inst->flags & MONO_INST_LMF) { + /* + * This variable represents a MonoLMF structure, which has no corresponding + * CLR type, so hard-code its size/alignment. + */ + size = sizeof (MonoLMF); + align = sizeof (mgreg_t); + reuse_slot = FALSE; + } + if (!reuse_slot) slot = 0xffffff; @@ -2064,7 +2198,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st #else gint32* -mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align) +mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align) { g_assert_not_reached (); return NULL; @@ -2072,12 +2206,6 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st #endif /* DISABLE_JIT */ -gint32* -mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align) -{ - return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align); -} - #define EMUL_HIT_SHIFT 3 #define EMUL_HIT_MASK ((1 << EMUL_HIT_SHIFT) - 1) /* small hit bitmap cache */ @@ -2234,6 +2362,8 @@ mono_bblock_insert_before_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_ { if (ins == NULL) { ins = bb->code; + if (ins) + ins->prev = ins_to_insert; bb->code = ins_to_insert; ins_to_insert->next = ins; if (bb->last_ins == NULL) @@ -2317,14 +2447,14 @@ mono_destroy_compile (MonoCompile *cfg) g_free (cfg); } -#ifdef MINI_HAVE_FAST_TLS -MINI_FAST_TLS_DECLARE(mono_lmf_addr); +#ifdef MONO_HAVE_FAST_TLS +MONO_FAST_TLS_DECLARE(mono_lmf_addr); #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR /* * When this is defined, the current lmf is stored in this tls variable instead of in * jit_tls->lmf. */ -MINI_FAST_TLS_DECLARE(mono_lmf); +MONO_FAST_TLS_DECLARE(mono_lmf); #endif #endif @@ -2337,21 +2467,17 @@ mono_get_jit_tls_key (void) gint32 mono_get_jit_tls_offset (void) { -#ifdef MINI_HAVE_FAST_TLS int offset; - MINI_THREAD_VAR_OFFSET (mono_jit_tls, offset); + MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset); return offset; -#else - return -1; -#endif } gint32 mono_get_lmf_tls_offset (void) { -#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) +#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) int offset; - MINI_THREAD_VAR_OFFSET(mono_lmf,offset); + MONO_THREAD_VAR_OFFSET(mono_lmf,offset); return offset; #else return -1; @@ -2362,22 +2488,25 @@ gint32 mono_get_lmf_addr_tls_offset (void) { int offset; - MINI_THREAD_VAR_OFFSET(mono_lmf_addr,offset); + MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset); return offset; } MonoLMF * mono_get_lmf (void) { -#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) - return MINI_FAST_TLS_GET (mono_lmf); +#if defined(MONO_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) + return MONO_FAST_TLS_GET (mono_lmf); #else MonoJitTlsData *jit_tls; if ((jit_tls = TlsGetValue (mono_jit_tls_id))) return jit_tls->lmf; - - g_assert_not_reached (); + /* + * We do not assert here because this function can be called from + * mini-gc.c on a thread that has not executed any managed code, yet + * (the thread object allocation can trigger a collection). + */ return NULL; #endif } @@ -2385,8 +2514,8 @@ mono_get_lmf (void) MonoLMF ** mono_get_lmf_addr (void) { -#ifdef MINI_HAVE_FAST_TLS - return MINI_FAST_TLS_GET (mono_lmf_addr); +#ifdef MONO_HAVE_FAST_TLS + return MONO_FAST_TLS_GET (mono_lmf_addr); #else MonoJitTlsData *jit_tls; @@ -2414,8 +2543,8 @@ mono_get_lmf_addr (void) void mono_set_lmf (MonoLMF *lmf) { -#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) - MINI_FAST_TLS_SET (mono_lmf, lmf); +#if defined(MONO_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) + MONO_FAST_TLS_SET (mono_lmf, lmf); #endif (*mono_get_lmf_addr ()) = lmf; @@ -2426,16 +2555,16 @@ mono_set_jit_tls (MonoJitTlsData *jit_tls) { TlsSetValue (mono_jit_tls_id, jit_tls); -#ifdef MINI_HAVE_FAST_TLS - MINI_FAST_TLS_SET (mono_jit_tls, jit_tls); +#ifdef MONO_HAVE_FAST_TLS + MONO_FAST_TLS_SET (mono_jit_tls, jit_tls); #endif } static void mono_set_lmf_addr (gpointer lmf_addr) { -#ifdef MINI_HAVE_FAST_TLS - MINI_FAST_TLS_SET (mono_lmf_addr, lmf_addr); +#ifdef MONO_HAVE_FAST_TLS + MONO_FAST_TLS_SET (mono_lmf_addr, lmf_addr); #endif } @@ -2450,13 +2579,17 @@ mono_jit_thread_attach (MonoDomain *domain) */ domain = mono_get_root_domain (); -#ifdef MINI_HAVE_FAST_TLS - if (!MINI_FAST_TLS_GET (mono_lmf_addr)) { +#ifdef MONO_HAVE_FAST_TLS + if (!MONO_FAST_TLS_GET (mono_lmf_addr)) { mono_thread_attach (domain); + // #678164 + mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background); } #else - if (!TlsGetValue (mono_jit_tls_id)) + if (!TlsGetValue (mono_jit_tls_id)) { mono_thread_attach (domain); + mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background); + } #endif if (mono_domain_get () != domain) mono_domain_set (domain, TRUE); @@ -2506,9 +2639,9 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func) jit_tls->first_lmf = lmf; -#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) +#if defined(MONO_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) /* jit_tls->lmf is unused */ - MINI_FAST_TLS_SET (mono_lmf, lmf); + MONO_FAST_TLS_SET (mono_lmf, lmf); mono_set_lmf_addr (&mono_lmf); #else mono_set_lmf_addr (&jit_tls->lmf); @@ -2719,10 +2852,11 @@ mono_patch_info_hash (gconstpointer data) switch (ji->type) { case MONO_PATCH_INFO_RVA: case MONO_PATCH_INFO_LDSTR: - case MONO_PATCH_INFO_TYPE_FROM_HANDLE: case MONO_PATCH_INFO_LDTOKEN: case MONO_PATCH_INFO_DECLSEC: return (ji->type << 8) | ji->data.token->token; + case MONO_PATCH_INFO_TYPE_FROM_HANDLE: + return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0); case MONO_PATCH_INFO_INTERNAL_METHOD: return (ji->type << 8) | g_str_hash (ji->data.name); case MONO_PATCH_INFO_VTABLE: @@ -2813,7 +2947,13 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, target = patch_info->data.inst->inst_c0 + code; break; case MONO_PATCH_INFO_IP: +#if defined(__native_client__) && defined(__native_client_codegen__) + /* Need to transform to the destination address, it's */ + /* emitted as an immediate in the code. */ + target = nacl_inverse_modify_patch_target(ip); +#else target = ip; +#endif break; case MONO_PATCH_INFO_METHOD_REL: target = code + patch_info->data.offset; @@ -2829,6 +2969,13 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, } case MONO_PATCH_INFO_METHOD_JUMP: target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE); +#if defined(__native_client__) && defined(__native_client_codegen__) +#if defined(TARGET_AMD64) + /* This target is an absolute address, not relative to the */ + /* current code being emitted on AMD64. */ + target = nacl_inverse_modify_patch_target(target); +#endif +#endif break; case MONO_PATCH_INFO_METHOD: if (patch_info->data.method == method) { @@ -2842,6 +2989,11 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, gpointer *jump_table; int i; +#if defined(__native_client__) && defined(__native_client_codegen__) + /* This memory will leak, but we don't care if we're */ + /* not deleting JIT'd methods anyway */ + jump_table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size); +#else if (method && method->dynamic) { jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size); } else { @@ -2851,10 +3003,27 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, jump_table = mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size); } } +#endif - for (i = 0; i < patch_info->data.table->table_size; i++) + for (i = 0; i < patch_info->data.table->table_size; i++) { +#if defined(__native_client__) && defined(__native_client_codegen__) + /* 'code' is relative to the current code blob, we */ + /* need to do this transform on it to make the */ + /* pointers in this table absolute */ + jump_table [i] = nacl_inverse_modify_patch_target (code) + GPOINTER_TO_INT (patch_info->data.table->table [i]); +#else jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]); +#endif + } + +#if defined(__native_client__) && defined(__native_client_codegen__) + /* jump_table is in the data section, we need to transform */ + /* it here so when it gets modified in amd64_patch it will */ + /* then point back to the absolute data address */ + target = nacl_inverse_modify_patch_target (jump_table); +#else target = jump_table; +#endif break; } case MONO_PATCH_INFO_METHODCONST: @@ -3054,6 +3223,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask); break; } + case MONO_PATCH_INFO_CASTCLASS_CACHE: { + target = mono_domain_alloc0 (domain, sizeof (gpointer)); + break; + } default: g_assert_not_reached (); } @@ -3200,11 +3373,18 @@ mono_postprocess_patches (MonoCompile *cfg) } case MONO_PATCH_INFO_SWITCH: { gpointer *table; +#if defined(__native_client__) && defined(__native_client_codegen__) + /* This memory will leak. */ + /* TODO: can we free this when */ + /* making the final jump table? */ + table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size); +#else if (cfg->method->dynamic) { table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size); } else { table = mono_domain_code_reserve (cfg->domain, sizeof (gpointer) * patch_info->data.table->table_size); } +#endif for (i = 0; i < patch_info->data.table->table_size; i++) { /* Might be NULL if the switch is eliminated */ @@ -3219,16 +3399,23 @@ mono_postprocess_patches (MonoCompile *cfg) break; } case MONO_PATCH_INFO_METHOD_JUMP: { - GSList *list; + MonoJumpList *jlist; MonoDomain *domain = cfg->domain; unsigned char *ip = cfg->native_code + patch_info->ip.i; +#if defined(__native_client__) && defined(__native_client_codegen__) + /* When this jump target gets evaluated, the method */ + /* will be installed in the dynamic code section, */ + /* not at the location of cfg->native_code. */ + ip = nacl_inverse_modify_patch_target (cfg->native_code) + patch_info->ip.i; +#endif mono_domain_lock (domain); - if (!domain_jit_info (domain)->jump_target_hash) - domain_jit_info (domain)->jump_target_hash = g_hash_table_new (NULL, NULL); - list = g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, patch_info->data.method); - list = g_slist_prepend (list, ip); - g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, patch_info->data.method, list); + jlist = g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, patch_info->data.method); + if (!jlist) { + jlist = mono_domain_alloc0 (domain, sizeof (MonoJumpList)); + g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, patch_info->data.method, jlist); + } + jlist->list = g_slist_prepend (jlist->list, ip); mono_domain_unlock (domain); break; } @@ -3360,6 +3547,26 @@ mono_codegen (MonoCompile *cfg) MonoBasicBlock *bb; int max_epilog_size; guint8 *code; + MonoDomain *code_domain; + + if (mono_using_xdebug) + /* + * Recent gdb versions have trouble processing symbol files containing + * overlapping address ranges, so allocate all code from the code manager + * of the root domain. (#666152). + */ + code_domain = mono_get_root_domain (); + else + code_domain = cfg->domain; + +#if defined(__native_client_codegen__) && defined(__native_client__) + void *code_dest; + + /* This keeps patch targets from being transformed during + * ordinary method compilation, for local branches and jumps. + */ + nacl_allow_target_modification (FALSE); +#endif for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { cfg->spill_count = 0; @@ -3413,6 +3620,9 @@ mono_codegen (MonoCompile *cfg) } } +#ifdef __native_client_codegen__ + mono_nacl_fix_patches (cfg->native_code, cfg->patch_info); +#endif mono_arch_emit_exceptions (cfg); max_epilog_size = 0; @@ -3435,17 +3645,26 @@ mono_codegen (MonoCompile *cfg) mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info); mono_domain_unlock (cfg->domain); - code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen); + if (mono_using_xdebug) + /* See the comment for cfg->code_domain */ + code = mono_domain_code_reserve (code_domain, cfg->code_size + unwindlen); + else + code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen); } else { guint unwindlen = 0; #ifdef MONO_ARCH_HAVE_UNWIND_TABLE unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo); #endif - code = mono_domain_code_reserve (cfg->domain, cfg->code_size + unwindlen); + code = mono_domain_code_reserve (code_domain, cfg->code_size + unwindlen); } +#if defined(__native_client_codegen__) && defined(__native_client__) + nacl_allow_target_modification (TRUE); +#endif memcpy (code, cfg->native_code, cfg->code_len); -#ifdef __native_client_codegen__ +#if defined(__default_codegen__) + g_free (cfg->native_code); +#elif defined(__native_client_codegen__) if (cfg->native_code_alloc) { g_free (cfg->native_code_alloc); cfg->native_code_alloc = 0; @@ -3453,9 +3672,7 @@ mono_codegen (MonoCompile *cfg) else if (cfg->native_code) { g_free (cfg->native_code); } -#else - g_free (cfg->native_code); -#endif +#endif /* __native_client_codegen__ */ cfg->native_code = code; code = cfg->native_code + cfg->code_len; @@ -3493,18 +3710,34 @@ if (valgrind_register){ #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO mono_arch_save_unwind_info (cfg); #endif - -#ifdef __native_client_codegen__ + +#if defined(__native_client_codegen__) && defined(__native_client__) + if (!cfg->compile_aot) { + if (cfg->method->dynamic) { + code_dest = nacl_code_manager_get_code_dest(cfg->dynamic_info->code_mp, cfg->native_code); + } else { + code_dest = nacl_domain_get_code_dest(cfg->domain, cfg->native_code); + } + } +#endif + +#if defined(__native_client_codegen__) mono_nacl_fix_patches (cfg->native_code, cfg->patch_info); #endif - mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors); + mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->dynamic_info ? cfg->dynamic_info->code_mp : NULL, cfg->run_cctors); if (cfg->method->dynamic) { - mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len); + if (mono_using_xdebug) + mono_domain_code_commit (code_domain, cfg->native_code, cfg->code_size, cfg->code_len); + else + mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len); } else { - mono_domain_code_commit (cfg->domain, cfg->native_code, cfg->code_size, cfg->code_len); + mono_domain_code_commit (code_domain, cfg->native_code, cfg->code_size, cfg->code_len); } +#if defined(__native_client_codegen__) && defined(__native_client__) + cfg->native_code = code_dest; +#endif mono_profiler_code_buffer_new (cfg->native_code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method); mono_arch_flush_icache (cfg->native_code, cfg->code_len); @@ -3720,9 +3953,8 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) /* * Extend the try block backwards to include parts of the previous call * instruction. - * FIXME: This is arch specific. */ - ei->try_start = (guint8*)ei->try_start - 1; + ei->try_start = (guint8*)ei->try_start - MONO_ARCH_MONITOR_ENTER_ADJUSTMENT; } tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len]; g_assert (tblock); @@ -5020,18 +5252,19 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in #ifndef DISABLE_JIT if (domain_jit_info (target_domain)->jump_target_hash) { MonoJumpInfo patch_info; - GSList *list, *tmp; - list = g_hash_table_lookup (domain_jit_info (target_domain)->jump_target_hash, method); - if (list) { + MonoJumpList *jlist; + GSList *tmp; + jlist = g_hash_table_lookup (domain_jit_info (target_domain)->jump_target_hash, method); + if (jlist) { patch_info.next = NULL; patch_info.ip.i = 0; patch_info.type = MONO_PATCH_INFO_METHOD_JUMP; patch_info.data.method = method; g_hash_table_remove (domain_jit_info (target_domain)->jump_target_hash, method); + + for (tmp = jlist->list; tmp; tmp = tmp->next) + mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, NULL, TRUE); } - for (tmp = list; tmp; tmp = tmp->next) - mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE); - g_slist_free (list); } mono_emit_jit_map (jinfo); @@ -5171,6 +5404,8 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method) { MonoJitDynamicMethodInfo *ji; gboolean destroy = TRUE; + GHashTableIter iter; + MonoJumpList *jlist; g_assert (method->dynamic); @@ -5180,11 +5415,31 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method) if (!ji) return; + mono_domain_lock (domain); g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method); mono_internal_hash_table_remove (&domain->jit_code_hash, method); g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method); g_hash_table_remove (domain_jit_info (domain)->runtime_invoke_hash, method); + + /* Remove jump targets in this method */ + g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash); + while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) { + GSList *tmp, *remove; + + remove = NULL; + for (tmp = jlist->list; tmp; tmp = tmp->next) { + guint8 *ip = tmp->data; + + if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size) + remove = g_slist_prepend (remove, tmp); + } + for (tmp = remove; tmp; tmp = tmp->next) { + jlist->list = g_slist_delete_link (jlist->list, tmp->data); + } + g_slist_free (remove); + } + mono_domain_unlock (domain); #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD @@ -5585,20 +5840,14 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler) } #endif - /* The hard-guard page has been hit: there is not much we can do anymore - * Print a hopefully clear message and abort. - */ if (jit_tls->stack_size && ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) { - const char *method; - /* we don't do much now, but we can warn the user with a useful message */ - fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr); - if (ji && ji->method) - method = mono_method_full_name (ji->method, TRUE); - else - method = "Unmanaged"; - fprintf (stderr, "At %s\n", method); - _exit (1); + /* + * The hard-guard page has been hit: there is not much we can do anymore + * Print a hopefully clear message and abort. + */ + mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr); + g_assert_not_reached (); } else { /* The original handler might not like that it is executed on an altstack... */ if (!ji && mono_chain_signal (SIG_HANDLER_PARAMS)) @@ -5728,6 +5977,8 @@ mini_parse_debug_options (void) debug_options.no_gdb_backtrace = TRUE; else if (!strcmp (arg, "suspend-on-sigsegv")) debug_options.suspend_on_sigsegv = TRUE; + else if (!strcmp (arg, "suspend-on-unhandled")) + debug_options.suspend_on_unhandled = TRUE; else if (!strcmp (arg, "dont-free-domains")) mono_dont_free_domains = TRUE; else if (!strcmp (arg, "dyn-runtime-invoke")) @@ -5744,7 +5995,7 @@ mini_parse_debug_options (void) debug_options.better_cast_details = TRUE; else { fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg); - fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n"); + fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'suspend-on-unhandled', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n"); exit (1); } } @@ -5820,6 +6071,7 @@ mini_create_jit_domain_info (MonoDomain *domain) info->runtime_invoke_hash = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free); info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, g_free); info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL); + info->jump_target_hash = g_hash_table_new (NULL, NULL); domain->runtime_info = info; } @@ -5827,7 +6079,8 @@ mini_create_jit_domain_info (MonoDomain *domain) static void delete_jump_list (gpointer key, gpointer value, gpointer user_data) { - g_slist_free (value); + MonoJumpList *jlist = value; + g_slist_free (jlist->list); } static void @@ -5855,10 +6108,8 @@ mini_free_jit_domain_info (MonoDomain *domain) { MonoJitDomainInfo *info = domain_jit_info (domain); - if (info->jump_target_hash) { - g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL); - g_hash_table_destroy (info->jump_target_hash); - } + g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL); + g_hash_table_destroy (info->jump_target_hash); if (info->jump_target_got_slot_hash) { g_hash_table_foreach (info->jump_target_got_slot_hash, delete_jump_list, NULL); g_hash_table_destroy (info->jump_target_got_slot_hash); @@ -5913,11 +6164,11 @@ mini_init (const char *filename, const char *runtime_version) mini_debugger_init (); #endif -#ifdef MINI_HAVE_FAST_TLS - MINI_FAST_TLS_INIT (mono_jit_tls); - MINI_FAST_TLS_INIT (mono_lmf_addr); +#ifdef MONO_HAVE_FAST_TLS + MONO_FAST_TLS_INIT (mono_jit_tls); + MONO_FAST_TLS_INIT (mono_lmf_addr); #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR - MINI_FAST_TLS_INIT (mono_lmf); + MONO_FAST_TLS_INIT (mono_lmf); #endif #endif @@ -5935,6 +6186,7 @@ mini_init (const char *filename, const char *runtime_version) callbacks.create_ftnptr = mini_create_ftnptr; callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr; callbacks.get_runtime_build_info = mono_get_runtime_build_info; + callbacks.set_cast_details = mono_set_cast_details; #ifdef MONO_ARCH_HAVE_IMT if (mono_use_imt) { @@ -5954,8 +6206,6 @@ mini_init (const char *filename, const char *runtime_version) mono_unwind_init (); - mini_gc_init (); - if (getenv ("MONO_XDEBUG")) { char *xdebug_opts = getenv ("MONO_XDEBUG"); mono_xdebug_init (xdebug_opts); @@ -6026,7 +6276,6 @@ mini_init (const char *filename, const char *runtime_version) #ifdef JIT_INVOKE_WORKS mono_install_runtime_invoke (mono_jit_runtime_invoke); #endif - mono_install_stack_walk (mono_jit_walk_stack); mono_install_get_cached_class_info (mono_aot_get_cached_class_info); mono_install_get_class_from_name (mono_aot_get_class_from_name); mono_install_jit_info_find_in_aot (mono_aot_find_jit_info); @@ -6056,10 +6305,12 @@ mini_init (const char *filename, const char *runtime_version) /* This must come after mono_init () in the aot-only case */ mono_exceptions_init (); - mono_install_handler (mono_get_throw_exception ()); mono_icall_init (); + /* This should come after mono_init () too */ + mini_gc_init (); + mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info); mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", @@ -6101,6 +6352,9 @@ mini_init (const char *filename, const char *runtime_version) register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE); register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE); +#if defined(__native_client__) || defined(__native_client_codegen__) + register_icall (mono_nacl_gc, "mono_nacl_gc", "void", TRUE); +#endif /* * NOTE, NOTE, NOTE, NOTE: * when adding emulation for some opcodes, remember to also add a dummy @@ -6123,10 +6377,6 @@ mini_init (const char *filename, const char *runtime_version) #endif #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV) - mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE); - mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE); - mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE); - mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE); mono_register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, FALSE); mono_register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE); mono_register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, FALSE); @@ -6134,13 +6384,10 @@ mini_init (const char *filename, const char *runtime_version) #endif #ifdef MONO_ARCH_EMULATE_MUL_DIV - mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE); mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE); #endif #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF) - mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE); - mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE); mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE); mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE); #endif @@ -6158,7 +6405,6 @@ mini_init (const char *filename, const char *runtime_version) mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE); #endif #ifdef MONO_ARCH_EMULATE_CONV_R8_UN - mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE); mono_register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, FALSE); #endif #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8 @@ -6171,7 +6417,11 @@ mini_init (const char *filename, const char *runtime_version) mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE); #endif #ifdef MONO_ARCH_EMULATE_FREM +#if defined(__default_codegen__) mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE); +#elif defined(__native_client_codegen__) + mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, FALSE); +#endif #endif #ifdef MONO_ARCH_SOFT_FLOAT @@ -6179,9 +6429,7 @@ mini_init (const char *filename, const char *runtime_version) mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE); mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE); mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE); - mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE); mono_register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, FALSE); - mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE); mono_register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, FALSE); mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE); mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);