#include <mono/utils/mono-hwcap.h>
#include <mono/utils/dtrace.h>
#include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
#include <mono/io-layer/io-layer.h>
#include "mini.h"
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->code_size = NACL_BUNDLE_ALIGN_UP (cfg->code_size);
-
- 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. */
-/* Instructions longer than 32 bytes must be aligned internally. */
-/* IN: pcode, instlen */
-/* OUT: pcode */
-void mono_nacl_align_inst(guint8 **pcode, int instlen) {
- int space_in_block;
-
- space_in_block = kNaClAlignment - ((uintptr_t)(*pcode) & kNaClAlignmentMask);
-
- if (G_UNLIKELY (instlen >= kNaClAlignment)) {
- g_assert_not_reached();
- } else if (instlen > space_in_block) {
- *pcode = mono_arch_nacl_pad(*pcode, space_in_block);
- }
}
-/* Move emitted call sequence to the end of a kNaClAlignment-byte block. */
-/* IN: start pointer to start of call sequence */
-/* IN: pcode pointer to end of call sequence (current "IP") */
-/* OUT: start pointer to the start of the call sequence after padding */
-/* OUT: pcode pointer to the end of the call sequence after padding */
-void mono_nacl_align_call(guint8 **start, guint8 **pcode) {
- const size_t MAX_NACL_CALL_LENGTH = kNaClAlignment;
- guint8 copy_of_call[MAX_NACL_CALL_LENGTH];
- guint8 *temp;
-
- const size_t length = (size_t)((*pcode)-(*start));
- g_assert(length < MAX_NACL_CALL_LENGTH);
-
- memcpy(copy_of_call, *start, length);
- temp = mono_nacl_pad_call(*start, (guint8)length);
- memcpy(temp, copy_of_call, length);
- (*start) = temp;
- (*pcode) = temp + length;
-}
-
-/* mono_nacl_pad_call(): Insert padding for Native Client call instructions */
-/* code pointer to buffer for emitting code */
-/* ilength length of call instruction */
-guint8 *mono_nacl_pad_call(guint8 *code, guint8 ilength) {
- int freeSpaceInBlock = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
- int padding = freeSpaceInBlock - ilength;
-
- if (padding < 0) {
- /* There isn't enough space in this block for the instruction. */
- /* Fill this block and start a new one. */
- code = mono_arch_nacl_pad(code, freeSpaceInBlock);
- freeSpaceInBlock = kNaClAlignment;
- padding = freeSpaceInBlock - ilength;
- }
- g_assert(ilength > 0);
- g_assert(padding >= 0);
- g_assert(padding < kNaClAlignment);
- if (0 == padding) return code;
- return mono_arch_nacl_pad(code, padding);
-}
-
-guint8 *mono_nacl_align(guint8 *code) {
- int padding = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
- if (padding != kNaClAlignment) code = mono_arch_nacl_pad(code, padding);
- return code;
-}
-
-void mono_nacl_fix_patches(const guint8 *code, MonoJumpInfo *ji)
-{
- MonoJumpInfo *patch_info;
- for (patch_info = ji; patch_info; patch_info = patch_info->next) {
- unsigned char *ip = patch_info->ip.i + code;
- ip = mono_arch_nacl_skip_nops(ip);
- patch_info->ip.i = ip - code;
- }
-}
-#endif /* __native_client_codegen__ */
-
typedef struct {
MonoExceptionClause *clause;
MonoBasicBlock *basic_block;
vars = g_list_prepend (vars, vmv);
}
- vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
+ vars = g_list_sort (vars, compare_by_interval_start_pos_func);
/* Sanity check */
/*
mono_verify_bblock (bb);
}
+// This will free many fields in cfg to save
+// memory. Note that this must be safe to call
+// multiple times. It must be idempotent.
+void
+mono_empty_compile (MonoCompile *cfg)
+{
+ mono_free_loop_info (cfg);
+
+ // These live in the mempool, and so must be freed
+ // first
+ for (GSList *l = cfg->headers_to_free; l; l = l->next) {
+ mono_metadata_free_mh ((MonoMethodHeader *)l->data);
+ }
+ cfg->headers_to_free = NULL;
+
+ if (cfg->mempool) {
+ //mono_mempool_stats (cfg->mempool);
+ mono_mempool_destroy (cfg->mempool);
+ cfg->mempool = NULL;
+ }
+
+ g_free (cfg->varinfo);
+ cfg->varinfo = NULL;
+
+ g_free (cfg->vars);
+ cfg->vars = NULL;
+
+ if (cfg->rs) {
+ mono_regstate_free (cfg->rs);
+ cfg->rs = NULL;
+ }
+}
+
void
mono_destroy_compile (MonoCompile *cfg)
{
- GSList *l;
+ mono_empty_compile (cfg);
if (cfg->header)
mono_metadata_free_mh (cfg->header);
- //mono_mempool_stats (cfg->mempool);
- mono_free_loop_info (cfg);
- if (cfg->rs)
- mono_regstate_free (cfg->rs);
+
if (cfg->spvars)
g_hash_table_destroy (cfg->spvars);
if (cfg->exvars)
g_hash_table_destroy (cfg->exvars);
- for (l = cfg->headers_to_free; l; l = l->next)
- mono_metadata_free_mh ((MonoMethodHeader *)l->data);
+
g_list_free (cfg->ldstr_list);
- g_hash_table_destroy (cfg->token_info_hash);
+
+ if (cfg->token_info_hash)
+ g_hash_table_destroy (cfg->token_info_hash);
+
if (cfg->abs_patches)
g_hash_table_destroy (cfg->abs_patches);
- mono_mempool_destroy (cfg->mempool);
mono_debug_free_method (cfg);
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);
jlist = (MonoJumpList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, patch_info->data.method);
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;
/* we reuse dfn here */
}
}
-#ifdef __native_client_codegen__
- mono_nacl_fix_patches (cfg->native_code, cfg->patch_info);
-#endif
mono_arch_emit_exceptions (cfg);
max_epilog_size = 0;
/* we always allocate code in cfg->domain->code_mp to increase locality */
cfg->code_size = cfg->code_len + max_epilog_size;
-#ifdef __native_client_codegen__
- cfg->code_size = NACL_BUNDLE_ALIGN_UP (cfg->code_size);
-#endif
+
/* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
} else {
code = (guint8 *)mono_domain_code_reserve (code_domain, cfg->code_size + cfg->thunk_area + unwindlen);
}
-#if defined(__native_client_codegen__) && defined(__native_client__)
- nacl_allow_target_modification (TRUE);
-#endif
+
if (cfg->thunk_area) {
cfg->thunks_offset = cfg->code_size + unwindlen;
cfg->thunks = code + cfg->thunks_offset;
g_assert (code);
memcpy (code, cfg->native_code, cfg->code_len);
-#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;
- }
- else if (cfg->native_code) {
- g_free (cfg->native_code);
- }
-#endif /* __native_client_codegen__ */
cfg->native_code = code;
code = cfg->native_code + cfg->code_len;
mono_arch_save_unwind_info (cfg);
#endif
-#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
-
#ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
{
MonoJumpInfo *ji;
}
}
#else
- mono_arch_patch_code (cfg, cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
+ mono_arch_patch_code (cfg, cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors, &cfg->error);
+ if (!is_ok (&cfg->error)) {
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
+ return;
+ }
#endif
if (cfg->method->dynamic) {
return FALSE;
}
+static void mono_insert_nop_in_empty_bb (MonoCompile *cfg)
+{
+ MonoBasicBlock *bb;
+ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ if (bb->code)
+ continue;
+ MonoInst *nop;
+ MONO_INST_NEW (cfg, nop, OP_NOP);
+ MONO_ADD_INS (bb, nop);
+ }
+}
static void
mono_create_gc_safepoint (MonoCompile *cfg, MonoBasicBlock *bblock)
{
if (info && info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER &&
(info->d.icall.func == mono_thread_interruption_checkpoint ||
- info->d.icall.func == mono_threads_finish_blocking ||
- info->d.icall.func == mono_threads_reset_blocking_start)) {
+ info->d.icall.func == mono_threads_exit_gc_safe_region_unbalanced)) {
/* These wrappers are called from the wrapper for the polling function, leading to potential stack overflow */
if (cfg->verbose_level > 1)
printf ("SKIPPING SAFEPOINTS for wrapper %s\n", cfg->method->name);
cfg->disable_omit_fp = debug_options.disable_omit_fp;
cfg->skip_visibility = method->skip_visibility;
cfg->orig_method = method;
- cfg->gen_seq_points = debug_options.gen_seq_points_compact_data || debug_options.gen_sdb_seq_points;
+ cfg->gen_seq_points = !debug_options.no_seq_points_compact_data || debug_options.gen_sdb_seq_points;
cfg->gen_sdb_seq_points = debug_options.gen_sdb_seq_points;
cfg->llvm_only = (flags & JIT_FLAG_LLVM_ONLY) != 0;
cfg->backend = current_backend;
cfg->gen_sdb_seq_points = FALSE;
}
#endif
+ if (cfg->method->wrapper_type == MONO_WRAPPER_ALLOC) {
+ /* We can't have seq points inside gc critical regions */
+ cfg->gen_seq_points = FALSE;
+ cfg->gen_sdb_seq_points = FALSE;
+ }
/* coop / nacl requires loop detection to happen */
#if defined(__native_client_codegen__)
cfg->opt |= MONO_OPT_LOOP;
//g_free (nm);
}
if (cfg->llvm_only) {
+ g_free (cfg->exception_message);
cfg->disable_aot = TRUE;
return cfg;
}
MONO_TIME_TRACK (mono_jit_stats.jit_method_to_ir, i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, NULL, NULL, 0, FALSE));
mono_cfg_dump_ir (cfg, "method-to-ir");
+ if (cfg->gdump_ctx != NULL) {
+ /* workaround for graph visualization, as it doesn't handle empty basic blocks properly */
+ mono_insert_nop_in_empty_bb (cfg);
+ mono_cfg_dump_ir (cfg, "mono_insert_nop_in_empty_bb");
+ }
+
if (i < 0) {
if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
if (compile_aot) {
mono_cfg_dump_ir (cfg, "local_cprop");
}
+ if (cfg->flags & MONO_CFG_HAS_TYPE_CHECK) {
+ MONO_TIME_TRACK (mono_jit_stats.jit_decompose_typechecks, mono_decompose_typechecks (cfg));
+ if (cfg->gdump_ctx != NULL) {
+ /* workaround for graph visualization, as it doesn't handle empty basic blocks properly */
+ mono_insert_nop_in_empty_bb (cfg);
+ }
+ mono_cfg_dump_ir (cfg, "decompose_typechecks");
+ }
+
/*
* Should be done after cprop which can do strength reduction on
* some of these ops, after propagating immediates.
mono_lookup_pinvoke_call (method, NULL, NULL);
}
nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
- code = mono_get_addr_from_ftnptr (mono_compile_method (nm));
+ gpointer compiled_method = mono_compile_method_checked (nm, error);
+ return_val_if_nok (error, NULL);
+ code = mono_get_addr_from_ftnptr (compiled_method);
jinfo = mono_jit_info_table_find (target_domain, (char *)code);
if (!jinfo)
jinfo = mono_jit_info_table_find (mono_domain_get (), (char *)code);
if (method->klass->parent == mono_defaults.multicastdelegate_class) {
if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
- MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
+ MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
g_assert (mi);
/*
* We need to make sure this wrapper
} else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
if (mono_llvm_only) {
nm = mono_marshal_get_delegate_invoke (method, NULL);
- return mono_get_addr_from_ftnptr (mono_compile_method (nm));
+ gpointer compiled_ptr = mono_compile_method_checked (nm, error);
+ mono_error_assert_ok (error);
+ return mono_get_addr_from_ftnptr (compiled_ptr);
}
return mono_create_delegate_trampoline (target_domain, method->klass);
} else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
nm = mono_marshal_get_delegate_begin_invoke (method);
- return mono_get_addr_from_ftnptr (mono_compile_method (nm));
+ gpointer compiled_ptr = mono_compile_method_checked (nm, error);
+ mono_error_assert_ok (error);
+ return mono_get_addr_from_ftnptr (compiled_ptr);
} else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
nm = mono_marshal_get_delegate_end_invoke (method);
- return mono_get_addr_from_ftnptr (mono_compile_method (nm));
+ gpointer compiled_ptr = mono_compile_method_checked (nm, error);
+ mono_error_assert_ok (error);
+ return mono_get_addr_from_ftnptr (compiled_ptr);
}
}
if (mono_aot_only) {
char *fullname = mono_method_full_name (method, TRUE);
- char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
-
- ex = mono_get_exception_execution_engine (msg);
- mono_error_set_exception_instance (error, ex);
+ mono_error_set_execution_engine (error, "Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
g_free (fullname);
- g_free (msg);
-
+
return NULL;
}
patch_info.data.method = method;
g_hash_table_remove (domain_jit_info (target_domain)->jump_target_hash, method);
-#if defined(__native_client_codegen__) && defined(__native_client__)
- /* These patches are applied after a method has been installed, no target munging is needed. */
- nacl_allow_target_modification (FALSE);
-#endif
#ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW
for (tmp = jlist->list; tmp; tmp = tmp->next) {
gpointer target = mono_resolve_patch_target (NULL, target_domain, (guint8 *)tmp->data, &patch_info, TRUE, error);
mono_arch_patch_code_new (NULL, target_domain, (guint8 *)tmp->data, &patch_info, target);
}
#else
- for (tmp = jlist->list; tmp; tmp = tmp->next)
- mono_arch_patch_code (NULL, NULL, target_domain, tmp->data, &patch_info, TRUE);
-#endif
-#if defined(__native_client_codegen__) && defined(__native_client__)
- nacl_allow_target_modification (TRUE);
+ for (tmp = jlist->list; tmp; tmp = tmp->next) {
+ mono_arch_patch_code (NULL, NULL, target_domain, tmp->data, &patch_info, TRUE, error);
+ if (!is_ok (error))
+ break;
+ }
#endif
}
}