/mono/mini/mini.c
C | 7546 lines | 5653 code | 1106 blank | 787 comment | 1283 complexity | f31ed2aa6d9086644678b23f82b25e3f MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
Large files files are truncated, but you can click here to view the full file
- /*
- * mini.c: The new Mono code generator.
- *
- * Authors:
- * Paolo Molaro (lupus@ximian.com)
- * Dietmar Maurer (dietmar@ximian.com)
- *
- * Copyright 2002-2003 Ximian, Inc.
- * Copyright 2003-2010 Novell, Inc.
- * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
- */
- #define MONO_LLVM_IN_MINI 1
- #include <config.h>
- #include <signal.h>
- #ifdef HAVE_ALLOCA_H
- #include <alloca.h>
- #endif
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <math.h>
- #ifdef HAVE_SYS_TIME_H
- #include <sys/time.h>
- #endif
- #include <mono/utils/memcheck.h>
- #include <mono/metadata/assembly.h>
- #include <mono/metadata/loader.h>
- #include <mono/metadata/tabledefs.h>
- #include <mono/metadata/class.h>
- #include <mono/metadata/object.h>
- #include <mono/metadata/tokentype.h>
- #include <mono/metadata/tabledefs.h>
- #include <mono/metadata/threads.h>
- #include <mono/metadata/appdomain.h>
- #include <mono/metadata/debug-helpers.h>
- #include <mono/io-layer/io-layer.h>
- #include "mono/metadata/profiler.h"
- #include <mono/metadata/profiler-private.h>
- #include <mono/metadata/mono-config.h>
- #include <mono/metadata/environment.h>
- #include <mono/metadata/mono-debug.h>
- #include <mono/metadata/gc-internal.h>
- #include <mono/metadata/threads-types.h>
- #include <mono/metadata/verify.h>
- #include <mono/metadata/verify-internals.h>
- #include <mono/metadata/mempool-internals.h>
- #include <mono/metadata/attach.h>
- #include <mono/metadata/runtime.h>
- #include <mono/utils/mono-math.h>
- #include <mono/utils/mono-compiler.h>
- #include <mono/utils/mono-counters.h>
- #include <mono/utils/mono-logger-internal.h>
- #include <mono/utils/mono-mmap.h>
- #include <mono/utils/mono-tls.h>
- #include <mono/utils/dtrace.h>
- #include "mini.h"
- #include "mini-llvm.h"
- #include "tasklets.h"
- #include <string.h>
- #include <ctype.h>
- #include "trace.h"
- #include "version.h"
- #include "jit-icalls.h"
- #include "debug-mini.h"
- #include "mini-gc.h"
- #include "debugger-agent.h"
- static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
- static guint32 default_opt = 0;
- static gboolean default_opt_set = FALSE;
- MonoNativeTlsKey mono_jit_tls_id;
- #ifdef MONO_HAVE_FAST_TLS
- MONO_FAST_TLS_DECLARE(mono_jit_tls);
- #endif
- #ifndef MONO_ARCH_MONITOR_ENTER_ADJUSTMENT
- #define MONO_ARCH_MONITOR_ENTER_ADJUSTMENT 1
- #endif
- MonoTraceSpec *mono_jit_trace_calls = NULL;
- gboolean mono_compile_aot = FALSE;
- /* If this is set, no code is generated dynamically, everything is taken from AOT files */
- gboolean mono_aot_only = FALSE;
- /* Whenever to use IMT */
- #ifdef MONO_ARCH_HAVE_IMT
- gboolean mono_use_imt = TRUE;
- #else
- gboolean mono_use_imt = FALSE;
- #endif
- MonoMethodDesc *mono_inject_async_exc_method = NULL;
- int mono_inject_async_exc_pos;
- MonoMethodDesc *mono_break_at_bb_method = NULL;
- int mono_break_at_bb_bb_num;
- gboolean mono_do_x86_stack_align = TRUE;
- const char *mono_build_date;
- gboolean mono_do_signal_chaining;
- static gboolean mono_using_xdebug;
- static int mini_verbose = 0;
- /*
- * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
- * it can load AOT code compiled by LLVM.
- */
- gboolean mono_use_llvm = FALSE;
- #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
- #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
- static CRITICAL_SECTION jit_mutex;
- static MonoCodeManager *global_codeman = NULL;
- static GHashTable *jit_icall_name_hash = NULL;
- static MonoDebugOptions debug_options;
- #ifdef VALGRIND_JIT_REGISTER_MAP
- static int valgrind_register = 0;
- #endif
- /*
- * Table written to by the debugger with a 1-based index into the
- * mono_breakpoint_info table, which contains changes made to
- * the JIT instructions by the debugger.
- */
- gssize
- mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
- /* Whenever to check for pending exceptions in managed-to-native wrappers */
- gboolean check_for_pending_exc = TRUE;
- /* Whenever to disable passing/returning small valuetypes in registers for managed methods */
- 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. */
- /* 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__ */
- gboolean
- mono_running_on_valgrind (void)
- {
- if (RUNNING_ON_VALGRIND){
- #ifdef VALGRIND_JIT_REGISTER_MAP
- valgrind_register = TRUE;
- #endif
- return TRUE;
- } else
- return FALSE;
- }
- typedef struct {
- MonoExceptionClause *clause;
- MonoBasicBlock *basic_block;
- int start_offset;
- } TryBlockHole;
- typedef struct {
- void *ip;
- MonoMethod *method;
- } FindTrampUserData;
- static void
- find_tramp (gpointer key, gpointer value, gpointer user_data)
- {
- FindTrampUserData *ud = (FindTrampUserData*)user_data;
- if (value == ud->ip)
- ud->method = (MonoMethod*)key;
- }
- /* debug function */
- G_GNUC_UNUSED static char*
- get_method_from_ip (void *ip)
- {
- MonoJitInfo *ji;
- char *method;
- char *res;
- MonoDomain *domain = mono_domain_get ();
- MonoDebugSourceLocation *location;
- FindTrampUserData user_data;
- if (!domain)
- domain = mono_get_root_domain ();
- ji = mono_jit_info_table_find (domain, ip);
- if (!ji) {
- user_data.ip = ip;
- user_data.method = NULL;
- mono_domain_lock (domain);
- g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
- mono_domain_unlock (domain);
- if (user_data.method) {
- char *mname = mono_method_full_name (user_data.method, TRUE);
- res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
- g_free (mname);
- return res;
- }
- else
- return NULL;
- }
- method = mono_method_full_name (ji->method, TRUE);
- /* FIXME: unused ? */
- location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
- res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
- mono_debug_free_source_location (location);
- g_free (method);
- return res;
- }
- /**
- * mono_pmip:
- * @ip: an instruction pointer address
- *
- * This method is used from a debugger to get the name of the
- * method at address @ip. This routine is typically invoked from
- * a debugger like this:
- *
- * (gdb) print mono_pmip ($pc)
- *
- * Returns: the name of the method at address @ip.
- */
- G_GNUC_UNUSED char *
- mono_pmip (void *ip)
- {
- return get_method_from_ip (ip);
- }
- /**
- * mono_print_method_from_ip
- * @ip: an instruction pointer address
- *
- * This method is used from a debugger to get the name of the
- * method at address @ip.
- *
- * This prints the name of the method at address @ip in the standard
- * 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)
- {
- MonoJitInfo *ji;
- char *method;
- MonoDebugSourceLocation *source;
- MonoDomain *domain = mono_domain_get ();
- MonoDomain *target_domain = mono_domain_get ();
- FindTrampUserData user_data;
- MonoGenericSharingContext*gsctx;
- const char *shared_type;
-
- ji = mini_jit_info_table_find (domain, ip, &target_domain);
- if (!ji) {
- user_data.ip = ip;
- user_data.method = NULL;
- mono_domain_lock (domain);
- g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
- mono_domain_unlock (domain);
- if (user_data.method) {
- char *mname = mono_method_full_name (user_data.method, TRUE);
- printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
- g_free (mname);
- }
- else
- g_print ("No method at %p\n", ip);
- fflush (stdout);
- return;
- }
- method = mono_method_full_name (ji->method, TRUE);
- source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
- gsctx = mono_jit_info_get_generic_sharing_context (ji);
- shared_type = "";
- if (gsctx) {
- if (gsctx->var_is_vt || gsctx->mvar_is_vt)
- shared_type = "gsharedvt ";
- else
- shared_type = "gshared ";
- }
- g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
- if (source)
- g_print ("%s:%d\n", source->source_file, source->row);
- fflush (stdout);
- mono_debug_free_source_location (source);
- g_free (method);
- }
-
- /*
- * mono_method_same_domain:
- *
- * Determine whenever two compiled methods are in the same domain, thus
- * the address of the callee can be embedded in the caller.
- */
- gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
- {
- if (!caller || !callee)
- return FALSE;
- /*
- * If the call was made from domain-neutral to domain-specific
- * code, we can't patch the call site.
- */
- if (caller->domain_neutral && !callee->domain_neutral)
- return FALSE;
- if ((caller->method->klass == mono_defaults.appdomain_class) &&
- (strstr (caller->method->name, "InvokeInDomain"))) {
- /* The InvokeInDomain methods change the current appdomain */
- return FALSE;
- }
- return TRUE;
- }
- /*
- * mono_global_codeman_reserve:
- *
- * Allocate code memory from the global code manager.
- */
- void *mono_global_codeman_reserve (int size)
- {
- void *ptr;
- if (mono_aot_only)
- g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
- if (!global_codeman) {
- /* This can happen during startup */
- global_codeman = mono_code_manager_new ();
- return mono_code_manager_reserve (global_codeman, size);
- }
- else {
- mono_jit_lock ();
- ptr = mono_code_manager_reserve (global_codeman, size);
- mono_jit_unlock ();
- return ptr;
- }
- }
- #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:
- *
- * Create an unwind op with the given parameters.
- */
- MonoUnwindOp*
- mono_create_unwind_op (int when, int tag, int reg, int val)
- {
- MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
- op->op = tag;
- op->reg = reg;
- op->val = val;
- op->when = when;
- return op;
- }
- /**
- * mono_emit_unwind_op:
- *
- * Add an unwind op with the given parameters for the list of unwind ops stored in
- * cfg->unwind_ops.
- */
- void
- mono_emit_unwind_op (MonoCompile *cfg, int when, int tag, int reg, int val)
- {
- MonoUnwindOp *op = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoUnwindOp));
- op->op = tag;
- op->reg = reg;
- op->val = val;
- op->when = when;
-
- cfg->unwind_ops = g_slist_append_mempool (cfg->mempool, cfg->unwind_ops, op);
- }
- MonoJumpInfoToken *
- mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
- {
- MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
- res->image = image;
- res->token = token;
- res->has_context = context != NULL;
- if (context)
- memcpy (&res->context, context, sizeof (MonoGenericContext));
- return res;
- }
- MonoJumpInfoToken *
- mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
- {
- return mono_jump_info_token_new2 (mp, image, token, NULL);
- }
-
- /*
- * mono_tramp_info_create:
- *
- * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
- * of NAME, JI, and UNWIND_OPS.
- */
- MonoTrampInfo*
- mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
- {
- MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
- info->name = (char*)name;
- info->code = code;
- info->code_size = code_size;
- info->ji = ji;
- info->unwind_ops = unwind_ops;
- return info;
- }
- void
- mono_tramp_info_free (MonoTrampInfo *info)
- {
- GSList *l;
- g_free (info->name);
- // FIXME: ji
- for (l = info->unwind_ops; l; l = l->next)
- g_free (l->data);
- g_slist_free (info->unwind_ops);
- g_free (info);
- }
- G_GNUC_UNUSED static void
- break_count (void)
- {
- }
- /*
- * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
- * Set a breakpoint in break_count () to break the last time <x> is done.
- */
- G_GNUC_UNUSED gboolean
- mono_debug_count (void)
- {
- static int count = 0;
- count ++;
- if (!getenv ("COUNT"))
- return TRUE;
- if (count == atoi (getenv ("COUNT"))) {
- break_count ();
- }
- if (count > atoi (getenv ("COUNT"))) {
- return FALSE;
- }
- return TRUE;
- }
- #define MONO_INIT_VARINFO(vi,id) do { \
- (vi)->range.first_use.pos.bid = 0xffff; \
- (vi)->reg = -1; \
- (vi)->idx = (id); \
- } while (0)
- /**
- * mono_unlink_bblock:
- *
- * Unlink two basic blocks.
- */
- void
- mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
- {
- int i, pos;
- gboolean found;
- found = FALSE;
- for (i = 0; i < from->out_count; ++i) {
- if (to == from->out_bb [i]) {
- found = TRUE;
- break;
- }
- }
- if (found) {
- pos = 0;
- for (i = 0; i < from->out_count; ++i) {
- if (from->out_bb [i] != to)
- from->out_bb [pos ++] = from->out_bb [i];
- }
- g_assert (pos == from->out_count - 1);
- from->out_count--;
- }
- found = FALSE;
- for (i = 0; i < to->in_count; ++i) {
- if (from == to->in_bb [i]) {
- found = TRUE;
- break;
- }
- }
- if (found) {
- pos = 0;
- for (i = 0; i < to->in_count; ++i) {
- if (to->in_bb [i] != from)
- to->in_bb [pos ++] = to->in_bb [i];
- }
- g_assert (pos == to->in_count - 1);
- to->in_count--;
- }
- }
- /*
- * mono_bblocks_linked:
- *
- * Return whenever BB1 and BB2 are linked in the CFG.
- */
- gboolean
- mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
- {
- int i;
- for (i = 0; i < bb1->out_count; ++i) {
- if (bb1->out_bb [i] == bb2)
- return TRUE;
- }
- return FALSE;
- }
- static int
- mono_find_block_region_notry (MonoCompile *cfg, int offset)
- {
- MonoMethodHeader *header = cfg->header;
- MonoExceptionClause *clause;
- int i;
- for (i = 0; i < header->num_clauses; ++i) {
- clause = &header->clauses [i];
- if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
- (offset < (clause->handler_offset)))
- return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
-
- if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
- if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
- return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
- else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
- return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
- else
- return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
- }
- }
- return -1;
- }
- /*
- * mono_get_block_region_notry:
- *
- * Return the region corresponding to REGION, ignoring try clauses nested inside
- * finally clauses.
- */
- int
- mono_get_block_region_notry (MonoCompile *cfg, int region)
- {
- if ((region & (0xf << 4)) == MONO_REGION_TRY) {
- MonoMethodHeader *header = cfg->header;
-
- /*
- * This can happen if a try clause is nested inside a finally clause.
- */
- int clause_index = (region >> 8) - 1;
- g_assert (clause_index >= 0 && clause_index < header->num_clauses);
-
- region = mono_find_block_region_notry (cfg, header->clauses [clause_index].try_offset);
- }
- return region;
- }
- MonoInst *
- mono_find_spvar_for_region (MonoCompile *cfg, int region)
- {
- region = mono_get_block_region_notry (cfg, region);
- return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
- }
- static void
- df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
- {
- int i;
- array [*dfn] = start;
- /* g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num); */
- for (i = 0; i < start->out_count; ++i) {
- if (start->out_bb [i]->dfn)
- continue;
- (*dfn)++;
- start->out_bb [i]->dfn = *dfn;
- start->out_bb [i]->df_parent = start;
- array [*dfn] = start->out_bb [i];
- df_visit (start->out_bb [i], dfn, array);
- }
- }
- guint32
- mono_reverse_branch_op (guint32 opcode)
- {
- static const int reverse_map [] = {
- CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
- CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
- };
- static const int reverse_fmap [] = {
- OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
- OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
- };
- static const int reverse_lmap [] = {
- OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
- OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
- };
- static const int reverse_imap [] = {
- OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
- OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
- };
-
- if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
- opcode = reverse_map [opcode - CEE_BEQ];
- } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
- opcode = reverse_fmap [opcode - OP_FBEQ];
- } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
- opcode = reverse_lmap [opcode - OP_LBEQ];
- } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
- opcode = reverse_imap [opcode - OP_IBEQ];
- } else
- g_assert_not_reached ();
- return opcode;
- }
- guint
- mono_type_to_store_membase (MonoCompile *cfg, MonoType *type)
- {
- if (type->byref)
- return OP_STORE_MEMBASE_REG;
- handle_enum:
- switch (type->type) {
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_BOOLEAN:
- return OP_STOREI1_MEMBASE_REG;
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- return OP_STOREI2_MEMBASE_REG;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- return OP_STOREI4_MEMBASE_REG;
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_FNPTR:
- return OP_STORE_MEMBASE_REG;
- case MONO_TYPE_CLASS:
- case MONO_TYPE_STRING:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_ARRAY:
- return OP_STORE_MEMBASE_REG;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- return OP_STOREI8_MEMBASE_REG;
- case MONO_TYPE_R4:
- return OP_STORER4_MEMBASE_REG;
- case MONO_TYPE_R8:
- return OP_STORER8_MEMBASE_REG;
- case MONO_TYPE_VALUETYPE:
- if (type->data.klass->enumtype) {
- type = mono_class_enum_basetype (type->data.klass);
- goto handle_enum;
- }
- if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
- return OP_STOREX_MEMBASE;
- return OP_STOREV_MEMBASE;
- case MONO_TYPE_TYPEDBYREF:
- return OP_STOREV_MEMBASE;
- case MONO_TYPE_GENERICINST:
- type = &type->data.generic_class->container_class->byval_arg;
- goto handle_enum;
- case MONO_TYPE_VAR:
- case MONO_TYPE_MVAR:
- if (mini_type_var_is_vt (cfg, type))
- return OP_STOREV_MEMBASE;
- else
- return OP_STORE_MEMBASE_REG;
- default:
- g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
- }
- return -1;
- }
- guint
- mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
- {
- if (type->byref)
- return OP_LOAD_MEMBASE;
- type = mono_type_get_underlying_type (type);
- switch (type->type) {
- case MONO_TYPE_I1:
- return OP_LOADI1_MEMBASE;
- case MONO_TYPE_U1:
- case MONO_TYPE_BOOLEAN:
- return OP_LOADU1_MEMBASE;
- case MONO_TYPE_I2:
- return OP_LOADI2_MEMBASE;
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- return OP_LOADU2_MEMBASE;
- case MONO_TYPE_I4:
- return OP_LOADI4_MEMBASE;
- case MONO_TYPE_U4:
- return OP_LOADU4_MEMBASE;
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_FNPTR:
- return OP_LOAD_MEMBASE;
- case MONO_TYPE_CLASS:
- case MONO_TYPE_STRING:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_ARRAY:
- return OP_LOAD_MEMBASE;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- return OP_LOADI8_MEMBASE;
- case MONO_TYPE_R4:
- return OP_LOADR4_MEMBASE;
- case MONO_TYPE_R8:
- return OP_LOADR8_MEMBASE;
- case MONO_TYPE_VALUETYPE:
- if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
- return OP_LOADX_MEMBASE;
- case MONO_TYPE_TYPEDBYREF:
- return OP_LOADV_MEMBASE;
- case MONO_TYPE_GENERICINST:
- if (mono_type_generic_inst_is_valuetype (type))
- return OP_LOADV_MEMBASE;
- else
- return OP_LOAD_MEMBASE;
- break;
- case MONO_TYPE_VAR:
- case MONO_TYPE_MVAR:
- g_assert (cfg->generic_sharing_context);
- if (mini_type_var_is_vt (cfg, type))
- return OP_LOADV_MEMBASE;
- else
- return OP_LOAD_MEMBASE;
- default:
- g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
- }
- return -1;
- }
- static guint
- mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
- {
- if (cfg->generic_sharing_context && !type->byref) {
- if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
- if (mini_type_var_is_vt (cfg, type))
- return CEE_LDOBJ;
- else
- return CEE_LDIND_REF;
- }
- }
- return mono_type_to_ldind (type);
- }
- #ifndef DISABLE_JIT
- guint
- mini_type_to_stind (MonoCompile* cfg, MonoType *type)
- {
- if (cfg->generic_sharing_context && !type->byref) {
- if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
- if (mini_type_var_is_vt (cfg, type))
- return CEE_STOBJ;
- else
- return CEE_STIND_REF;
- }
- }
- return mono_type_to_stind (type);
- }
- int
- mono_op_imm_to_op (int opcode)
- {
- switch (opcode) {
- case OP_ADD_IMM:
- #if SIZEOF_REGISTER == 4
- return OP_IADD;
- #else
- return OP_LADD;
- #endif
- case OP_IADD_IMM:
- return OP_IADD;
- case OP_LADD_IMM:
- return OP_LADD;
- case OP_ISUB_IMM:
- return OP_ISUB;
- case OP_LSUB_IMM:
- return OP_LSUB;
- case OP_IMUL_IMM:
- return OP_IMUL;
- case OP_AND_IMM:
- #if SIZEOF_REGISTER == 4
- return OP_IAND;
- #else
- return OP_LAND;
- #endif
- case OP_OR_IMM:
- #if SIZEOF_REGISTER == 4
- return OP_IOR;
- #else
- return OP_LOR;
- #endif
- case OP_XOR_IMM:
- #if SIZEOF_REGISTER == 4
- return OP_IXOR;
- #else
- return OP_LXOR;
- #endif
- case OP_IAND_IMM:
- return OP_IAND;
- case OP_LAND_IMM:
- return OP_LAND;
- case OP_IOR_IMM:
- return OP_IOR;
- case OP_LOR_IMM:
- return OP_LOR;
- case OP_IXOR_IMM:
- return OP_IXOR;
- case OP_LXOR_IMM:
- return OP_LXOR;
- case OP_ISHL_IMM:
- return OP_ISHL;
- case OP_LSHL_IMM:
- return OP_LSHL;
- case OP_ISHR_IMM:
- return OP_ISHR;
- case OP_LSHR_IMM:
- return OP_LSHR;
- case OP_ISHR_UN_IMM:
- return OP_ISHR_UN;
- case OP_LSHR_UN_IMM:
- return OP_LSHR_UN;
- case OP_IDIV_IMM:
- return OP_IDIV;
- case OP_IDIV_UN_IMM:
- return OP_IDIV_UN;
- case OP_IREM_UN_IMM:
- return OP_IREM_UN;
- case OP_IREM_IMM:
- return OP_IREM;
- case OP_DIV_IMM:
- #if SIZEOF_REGISTER == 4
- return OP_IDIV;
- #else
- return OP_LDIV;
- #endif
- case OP_REM_IMM:
- #if SIZEOF_REGISTER == 4
- return OP_IREM;
- #else
- return OP_LREM;
- #endif
- case OP_ADDCC_IMM:
- return OP_ADDCC;
- case OP_ADC_IMM:
- return OP_ADC;
- case OP_SUBCC_IMM:
- return OP_SUBCC;
- case OP_SBB_IMM:
- return OP_SBB;
- case OP_IADC_IMM:
- return OP_IADC;
- case OP_ISBB_IMM:
- return OP_ISBB;
- case OP_COMPARE_IMM:
- return OP_COMPARE;
- case OP_ICOMPARE_IMM:
- return OP_ICOMPARE;
- case OP_LOCALLOC_IMM:
- return OP_LOCALLOC;
- default:
- printf ("%s\n", mono_inst_name (opcode));
- g_assert_not_reached ();
- return -1;
- }
- }
- /*
- * mono_decompose_op_imm:
- *
- * Replace the OP_.._IMM INS with its non IMM variant.
- */
- void
- mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
- {
- MonoInst *temp;
- MONO_INST_NEW (cfg, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_alloc_ireg (cfg);
- mono_bblock_insert_before_ins (bb, ins, temp);
- ins->opcode = mono_op_imm_to_op (ins->opcode);
- if (ins->opcode == OP_LOCALLOC)
- ins->sreg1 = temp->dreg;
- else
- ins->sreg2 = temp->dreg;
- bb->max_vreg = MAX (bb->max_vreg, cfg->next_vreg);
- }
- #endif
- static void
- set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
- {
- if (vreg >= cfg->vreg_to_inst_len) {
- MonoInst **tmp = cfg->vreg_to_inst;
- int size = cfg->vreg_to_inst_len;
- while (vreg >= cfg->vreg_to_inst_len)
- cfg->vreg_to_inst_len = cfg->vreg_to_inst_len ? cfg->vreg_to_inst_len * 2 : 32;
- cfg->vreg_to_inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * cfg->vreg_to_inst_len);
- if (size)
- memcpy (cfg->vreg_to_inst, tmp, size * sizeof (MonoInst*));
- }
- cfg->vreg_to_inst [vreg] = inst;
- }
- #define mono_type_is_long(type) (!(type)->byref && ((mono_type_get_underlying_type (type)->type == MONO_TYPE_I8) || (mono_type_get_underlying_type (type)->type == MONO_TYPE_U8)))
- #define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
- #ifdef DISABLE_JIT
- MonoInst*
- mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
- {
- return NULL;
- }
- #else
- MonoInst*
- mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, int vreg)
- {
- MonoInst *inst;
- int num = cfg->num_varinfo;
- gboolean regpair;
- if ((num + 1) >= cfg->varinfo_count) {
- int orig_count = cfg->varinfo_count;
- cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
- cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
- cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
- memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
- }
- cfg->stat_allocate_var++;
- MONO_INST_NEW (cfg, inst, opcode);
- inst->inst_c0 = num;
- inst->inst_vtype = type;
- inst->klass = mono_class_from_mono_type (type);
- type_to_eval_stack_type (cfg, type, inst);
- /* if set to 1 the variable is native */
- inst->backend.is_pinvoke = 0;
- inst->dreg = vreg;
- if (inst->klass->exception_type)
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
- if (cfg->compute_gc_maps) {
- 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;
- MONO_INIT_VARINFO (&cfg->vars [num], num);
- MONO_VARINFO (cfg, num)->vreg = vreg;
- if (vreg != -1)
- set_vreg_to_inst (cfg, vreg, inst);
- #if SIZEOF_REGISTER == 4
- #ifdef MONO_ARCH_SOFT_FLOAT
- regpair = mono_type_is_long (type) || mono_type_is_float (type);
- #else
- regpair = mono_type_is_long (type);
- #endif
- #else
- regpair = FALSE;
- #endif
- if (regpair) {
- MonoInst *tree;
- /*
- * These two cannot be allocated using create_var_for_vreg since that would
- * put it into the cfg->varinfo array, confusing many parts of the JIT.
- */
- /*
- * Set flags to VOLATILE so SSA skips it.
- */
- if (cfg->verbose_level >= 4) {
- printf (" Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
- }
- #ifdef MONO_ARCH_SOFT_FLOAT
- if (cfg->opt & MONO_OPT_SSA) {
- if (mono_type_is_float (type))
- inst->flags = MONO_INST_VOLATILE;
- }
- #endif
- /* Allocate a dummy MonoInst for the first vreg */
- MONO_INST_NEW (cfg, tree, OP_LOCAL);
- tree->dreg = inst->dreg + 1;
- if (cfg->opt & MONO_OPT_SSA)
- tree->flags = MONO_INST_VOLATILE;
- tree->inst_c0 = num;
- tree->type = STACK_I4;
- tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
- tree->klass = mono_class_from_mono_type (tree->inst_vtype);
- set_vreg_to_inst (cfg, inst->dreg + 1, tree);
- /* Allocate a dummy MonoInst for the second vreg */
- MONO_INST_NEW (cfg, tree, OP_LOCAL);
- tree->dreg = inst->dreg + 2;
- if (cfg->opt & MONO_OPT_SSA)
- tree->flags = MONO_INST_VOLATILE;
- tree->inst_c0 = num;
- tree->type = STACK_I4;
- tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
- tree->klass = mono_class_from_mono_type (tree->inst_vtype);
- set_vreg_to_inst (cfg, inst->dreg + 2, tree);
- }
- cfg->num_varinfo++;
- if (cfg->verbose_level > 2)
- g_print ("created temp %d (R%d) of type %s\n", num, vreg, mono_type_get_name (type));
- return inst;
- }
- MonoInst*
- mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
- {
- int dreg;
- if (mono_type_is_long (type))
- dreg = mono_alloc_dreg (cfg, STACK_I8);
- #ifdef MONO_ARCH_SOFT_FLOAT
- else if (mono_type_is_float (type))
- dreg = mono_alloc_dreg (cfg, STACK_R8);
- #endif
- else
- /* All the others are unified */
- dreg = mono_alloc_preg (cfg);
- return mono_compile_create_var_for_vreg (cfg, type, opcode, dreg);
- }
- /*
- * Transform a MonoInst into a load from the variable of index var_index.
- */
- void
- mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
- memset (dest, 0, sizeof (MonoInst));
- dest->inst_i0 = cfg->varinfo [var_index];
- dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
- type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
- dest->klass = dest->inst_i0->klass;
- }
- #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) {
- case STACK_I4: return &mono_defaults.int32_class->byval_arg;
- case STACK_I8: return &mono_defaults.int64_class->byval_arg;
- case STACK_PTR: return &mono_defaults.int_class->byval_arg;
- case STACK_R8: return &mono_defaults.double_class->byval_arg;
- case STACK_MP:
- /*
- * this if used to be commented without any specific reason, but
- * it breaks #80235 when commented
- */
- if (ins->klass)
- return &ins->klass->this_arg;
- else
- return &mono_defaults.object_class->this_arg;
- case STACK_OBJ:
- /* ins->klass may not be set for ldnull.
- * Also, if we have a boxed valuetype, we want an object lass,
- * not the valuetype class
- */
- if (ins->klass && !ins->klass->valuetype)
- return &ins->klass->byval_arg;
- return &mono_defaults.object_class->byval_arg;
- case STACK_VTYPE: return &ins->klass->byval_arg;
- default:
- g_error ("stack type %d to montype not handled\n", ins->type);
- }
- return NULL;
- }
- MonoType*
- mono_type_from_stack_type (MonoInst *ins) {
- return type_from_stack_type (ins);
- }
- /*
- * mono_add_ins_to_end:
- *
- * Same as MONO_ADD_INS, but add INST before any branches at the end of BB.
- */
- void
- mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
- {
- int opcode;
- if (!bb->code) {
- MONO_ADD_INS (bb, inst);
- return;
- }
- switch (bb->last_ins->opcode) {
- case OP_BR:
- case OP_BR_REG:
- case CEE_BEQ:
- case CEE_BGE:
- case CEE_BGT:
- case CEE_BLE:
- case CEE_BLT:
- case CEE_BNE_UN:
- case CEE_BGE_UN:
- case CEE_BGT_UN:
- case CEE_BLE_UN:
- case CEE_BLT_UN:
- case OP_SWITCH:
- mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
- break;
- default:
- if (MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
- /* Need to insert the ins before the compare */
- if (bb->code == bb->last_ins) {
- mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
- return;
- }
- if (bb->code->next == bb->last_ins) {
- /* Only two instructions */
- opcode = bb->code->opcode;
- if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
- /* NEW IR */
- mono_bblock_insert_before_ins (bb, bb->code, inst);
- } else {
- mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
- }
- } else {
- opcode = bb->last_ins->prev->opcode;
- if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
- /* NEW IR */
- mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst);
- } else {
- mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
- }
- }
- }
- else
- MONO_ADD_INS (bb, inst);
- break;
- }
- }
- void
- mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
- {
- MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
- MonoJumpInfoBBTable *table;
- table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
- table->table = bbs;
- table->table_size = num_blocks;
-
- ji->ip.label = label;
- ji->type = MONO_PATCH_INFO_SWITCH;
- ji->data.table = table;
- ji->next = cfg->patch_info;
- cfg->patch_info = ji;
- }
- static MonoMethodSignature *
- mono_get_array_new_va_signature (int arity)
- {
- static GHashTable *sighash = NULL;
- MonoMethodSignature *res;
- int i;
- mono_jit_lock ();
- if (!sighash) {
- sighash = g_hash_table_new (NULL, NULL);
- }
- else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
- mono_jit_unlock ();
- return res;
- }
- res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
- res->pinvoke = 1;
- #ifdef MONO_ARCH_VARARG_ICALLS
- /* Only set this only some archs since not all backends can handle varargs+pinvoke */
- res->call_convention = MONO_CALL_VARARG;
- #endif
- #ifdef TARGET_WIN32
- res->call_convention = MONO_CALL_C;
- #endif
- res->params [0] = &mono_defaults.int_class->byval_arg;
- for (i = 0; i < arity; i++)
- res->params [i + 1] = &mono_defaults.int_class->byval_arg;
- res->ret = &mono_defaults.object_class->byval_arg;
- g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
- mono_jit_unlock ();
- return res;
- }
- MonoJitICallInfo *
- mono_get_array_new_va_icall (int rank)
- {
- MonoMethodSignature *esig;
- char icall_name [256];
- char *name;
- MonoJitICallInfo *info;
- /* Need to register the icall so it gets an icall wrapper */
- sprintf (icall_name, "ves_array_new_va_%d", rank);
- mono_jit_lock ();
- info = mono_find_jit_icall_by_name (icall_name);
- if (info == NULL) {
- esig = mono_get_array_new_va_signature (rank);
- name = g_strdup (icall_name);
- info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
- g_hash_table_insert (jit_icall_name_hash, name, name);
- }
- mono_jit_unlock ();
- return info;
- }
- gboolean
- mini_class_is_system_array (MonoClass *klass)
- {
- if (klass->parent == mono_defaults.array_class)
- return TRUE;
- else
- return FALSE;
- }
- gboolean
- mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
- {
- MonoAssembly *assembly = method->klass->image->assembly;
- if (method->wrapper_type != MONO_WRAPPER_NONE && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
- return FALSE;
- if (assembly->in_gac || assembly->image == mono_defaults.corlib)
- return FALSE;
- if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE)
- return FALSE;
- return mono_assembly_has_skip_verification (assembly);
- }
- /*
- * mini_method_verify:
- *
- * Verify the method using the new verfier.
- *
- * Returns true if the method is invalid.
- */
- static gboolean
- mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
- {
- GSList *tmp, *res;
- gboolean is_fulltrust;
- MonoLoaderError *error;
- if (method->verification_success)
- return FALSE;
- if (!mono_verifier_is_enabled_for_method (method))
- return FALSE;
- /*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)
- cfg->exception_type = error->exception_type;
- else
- mono_loader_clear_error ();
- if (res)
- mono_free_verify_list (res);
- return TRUE;
- }
- if (res) {
- for (tmp = res; tmp; tmp = tmp->next) {
- MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data;
- if (info->info.status == MONO_VERIFY_ERROR) {
- if (fail_compile) {
- char *method_name = mono_method_full_name (method, TRUE);
- cfg->exception_type = info->exception_type;
- cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
- g_free (method_name);
- }
- mono_free_verify_list (res);
- return TRUE;
- }
- if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && (!is_fulltrust || info->exception_type == MONO_EXCEPTION_METHOD_ACCESS || info->exception_type == MONO_EXCEPTION_FIELD_ACCESS)) {
- if (fail_compile) {
- char *method_name = mono_method_full_name (method, TRUE);
- cfg->exception_type = info->exception_type;
- cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
- g_free (method_name);
- }
- mono_free_verify_list (res);
- return TRUE;
- }
- }
- mono_free_verify_list (res);
- }
- method->verification_success = 1;
- return FALSE;
- }
- /*Returns true if something went wrong*/
- gboolean
- mono_compile_is_broken (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
- {
- MonoMethod *method_definition = method;
- gboolean dont_verify = method->klass->image->assembly->corlib_internal;
- while (method_definition->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
- method_definition = imethod->declaring;
- }
- return !dont_verify && mini_method_verify (cfg, method_definition, fail_compile);
- }
- static gconstpointer
- mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
- {
- char *name;
- MonoMethod *wrapper;
- gconstpointer trampoline;
- MonoDomain *domain = mono_get_root_domain ();
-
- if (callinfo->wrapper) {
- return callinfo->wrapper;
- }
- if (callinfo->trampoline)
- return callinfo->trampoline;
- /*
- * We use the lock on the root domain instead of the JIT lock to protect
- * callinfo->trampoline, since we do a lot of stuff inside the critical section.
- */
- mono_loader_lock (); /*FIXME mono_compile_method requires the loader lock, by large.*/
- mono_domain_lock (domain);
- if (callinfo->trampoline) {
- mono_domain_unlock (domain);
- mono_loader_unlock ();
- return callinfo->trampoline;
- }
- name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
- wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
- g_free (name);
- if (do_compile)
- trampoline = mono_compile_method (wrapper);
- else
- trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
- mono_register_jit_icall_wrapper (callinfo, trampoline);
- callinfo->trampoline = trampoline;
- mono_domain_unlock (domain);
- mono_loader_unlock ();
-
- return callinfo->trampoline;
- }
- gconstpointer
- mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
- {
- return mono_icall_get_wrapper_full (callinfo, FALSE);
- }
- static void
- mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
- {
- if (!domain_jit_info (domain)->dynamic_code_hash)
- domain_jit_info (domain)->dynamic_code_hash = g_hash_table_new (NULL, NULL);
- g_hash_table_insert (domain_jit_info (domain)->dynamic_code_hash, method, ji);
- }
- static MonoJitDynamicMethodInfo*
- mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
- {
- MonoJitDynamicMethodInfo *res;
- if (domain_jit_info (domain)->dynamic_code_hash)
- res = g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
- else
- res = NULL;
- return res;
- }
- typedef struct {
- MonoClass *vtype;
- GList *active, *inactive;
- GSList *slots;
- } StackSlotInfo;
- static gint
- compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
- {
- MonoMethodVar *v1 = (MonoMethodVar*)a;
- MonoMethodVar *v2 = (MonoMethodVar*)b;
- if (v1 == v2)
- return 0;
- else if (v1->interval->range && v2->interval->range)
- return v1->interval->range->from - v2->interval->range->from;
- else if (v1->interval->range)
- return -1;
- else
- return 1;
- }
- #ifndef DISABLE_JIT
- #if 0
- #define LSCAN_DEBUG(a) do { a; } while (0)
- #else
- #define LSCAN_DEBUG(a)
- #endif
- static gint32*
- mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
- {
- int i, slot, offset, size;
- guint32 align;
- MonoMethodVar *vmv;
- MonoInst *inst;
- gint32 *offsets;
- GList *vars = NULL, *l, *unhandled;
- StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
- MonoType *t;
- int nvtypes;
- gboolean reuse_slot;
- LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg->method, TRUE)));
- scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
- vtype_stack_slots = NULL;
- nvtypes = 0;
- offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
- for (i = 0; i < cfg->num_varinfo; ++i)
- offsets [i] = -1;
- for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
- inst = cfg->varinfo [i];
- vmv = MONO_VARINFO (cfg, i);
- if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
- continue;
- vars = g_list_prepend (vars, vmv);
- }
- vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
- /* Sanity check */
- /*
- i = 0;
- for (unhandled = vars; unhandled; unhandled = unhandled->next) {
- MonoMethodVar *current = unhandled->data;
- if (current->interval->range) {
- g_assert (current->interval->range->from >= i);
- i = current->interval->range->from;
- }
- }
- */
- offset = 0;
- *stack_align = 0;
- for (unhandled = vars; unhandled; unhandled = unhandled->next) {
- MonoMethodVar *current = unhandled->data;
- vmv = current;
- inst = cfg->varinfo [vmv->idx];
- t = mono_type_get_underlying_type (inst->inst_vtype);
- if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
- t = mini_get_gsharedvt_alloc_type_for_type (cfg, t);
- /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
- * pinvoke wrappers when they call functions returning structures */
- if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) {
- size = mono_class_native_size (mono_class_from_mono_type (t), &align);
- }
- else {
- int ialign;
- size = mono_type_size (t, &ialign);
- align = ialign;
- if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t)))
- align = 16;
- }
- reuse_slot = TRUE;
- if (cfg->disable_reuse_stack_slots)
- reuse_slot = FALSE;
- switch (t->type) {
- case MONO_TYPE_GENERICINST:
- if (!mono_type_generic_inst_is_valuetype (t)) {
- slot_info = &scalar_stack_slots [t->type];
- break;
- }
- /* Fall through */
- case MONO_TYPE_VALUETYPE:
- if (!vtype_stack_slots)
- vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
- for (i = 0; i < nvtypes; ++i)
- if (t->data.klass == vtype_stack_slots [i].vtype)
- break;
- if (i < nvtypes)
- slot_info = &vtype_stack_slots [i];
- else {
- g_assert (nvtypes < 256);
- vtype_stack_slots [nvtypes].vtype = t->data.klass;
- slot_info = &vtype_stack_slots [nvtypes];
- nvtypes ++;
- }
- if (cfg->disable_reuse_ref_stack_slots)
- reuse_slot = FALSE;
- break;
- case MONO_TYPE_PTR:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- #if SIZEOF_VOID_P == 4
- case MONO_TYPE_I4:
- #else
- case MONO_TYPE_I8:
- #endif
- if (cfg->disable_ref_noref_stack_slot_share) {
- slot_info = &scalar_stack_slots [MONO_TYPE_I];
- break;
- }
- /* Fall through */
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_STRING:
- /* Share non-float stack slots of the same size */
- slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
- if (cfg->disable_reuse_ref_stack_slots)
- reuse_slot = FALSE;
- break;
- default:
- slot_info = &scalar_stack_slots [t->type];
- }
- slot = 0xffffff;
- if (cfg->comp_done & MONO_COMP_LIVENESS) {
- int pos;
- gboolean changed;
- //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
- if (!current->interval->range) {
- if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
- pos = ~0;
- else {
- /* Dead */
- inst->flags |= MONO_INST_IS_DEAD;
- continue;
- }
- }
- else
- pos = current->interval->range->from;
- LSCAN_DEBUG (printf ("process R%d ", inst->dreg));
- if (current->interval->range)
- LSCAN_DEBUG (mono_linterval_print (current->interval));
- LSCAN_DEBUG (printf ("\n"));
- /* Check for intervals in active which expired or inactive */
- changed = TRUE;
- /* FIXME: Optimize this */
- while (changed) {
- changed = FALSE;
- for (l = slot_info->active; l != NULL; l = l->next) {
- MonoMethodVar *v = (MonoMethodVar*)l->data;
- if (v->interval->last_range->to < pos) {
- slot_info->active = g_list_delete_link (slot_info->active, l);
- slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->id…
Large files files are truncated, but you can click here to view the full file