-/*
- * method-to-ir.c: Convert CIL to the JIT internal representation
+/**
+ * \file
+ * Convert CIL to the JIT internal representation
*
* Author:
* Paolo Molaro (lupus@ximian.com)
#include <config.h>
#include <mono/utils/mono-compiler.h>
+#include "mini.h"
#ifndef DISABLE_JIT
#endif
#include <mono/utils/memcheck.h>
-#include "mini.h"
#include <mono/metadata/abi-details.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/attrdefs.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/debug-helpers.h>
-#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/mono-debug-debugger.h>
+#include <mono/metadata/debug-internals.h>
#include <mono/metadata/gc-internals.h>
#include <mono/metadata/security-manager.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/profiler.h>
#include <mono/metadata/monitor.h>
-#include <mono/metadata/debug-mono-symfile.h>
-#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-memory-model.h>
#include <mono/utils/mono-error-internals.h>
#include <mono/metadata/mono-basic-block.h>
int mono_op_to_op_imm (int opcode);
int mono_op_to_op_imm_noemul (int opcode);
-MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
-
static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
guchar *ip, guint real_offset, gboolean inline_always);
static MonoInst*
emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
+inline static MonoInst*
+mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg);
+
/* helper methods signatures */
static MonoMethodSignature *helper_sig_domain_get;
static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
static MonoMethodSignature *helper_sig_jit_thread_attach;
+static MonoMethodSignature *helper_sig_get_tls_tramp;
+static MonoMethodSignature *helper_sig_set_tls_tramp;
/* type loading helpers */
-static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
-static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
+static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, "System.Runtime.CompilerServices", "RuntimeHelpers")
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, "System.Diagnostics", "DebuggableAttribute")
/*
* Instruction metadata
#undef MINI_OP
#undef MINI_OP3
-#define MONO_INIT_VARINFO(vi,id) do { \
- (vi)->range.first_use.pos.bid = 0xffff; \
- (vi)->reg = -1; \
- (vi)->idx = (id); \
-} while (0)
-
guint32
mono_alloc_ireg (MonoCompile *cfg)
{
{
int i;
MonoInst *tree;
+ GString *str = g_string_new ("");
- printf ("\n%s %d: [IN: ", msg, bb->block_num);
+ g_string_append_printf (str, "%s %d: [IN: ", msg, bb->block_num);
for (i = 0; i < bb->in_count; ++i)
- printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
- printf (", OUT: ");
+ g_string_append_printf (str, " BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
+ g_string_append_printf (str, ", OUT: ");
for (i = 0; i < bb->out_count; ++i)
- printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
- printf (" ]\n");
+ g_string_append_printf (str, " BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
+ g_string_append_printf (str, " ]\n");
+
+ g_print ("%s", str->str);
+ g_string_free (str, TRUE);
+
for (tree = bb->code; tree; tree = tree->next)
mono_print_ins_index (-1, tree);
}
helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
+ helper_sig_get_tls_tramp = mono_create_icall_signature ("ptr");
+ helper_sig_set_tls_tramp = mono_create_icall_signature ("void ptr");
}
static MONO_NEVER_INLINE void
return cfg->got_var;
}
-static MonoInst *
-mono_get_vtable_var (MonoCompile *cfg)
+static void
+mono_create_rgctx_var (MonoCompile *cfg)
{
- g_assert (cfg->gshared);
-
if (!cfg->rgctx_var) {
cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
/* force the var to be stack allocated */
cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
}
+}
+
+static MonoInst *
+mono_get_vtable_var (MonoCompile *cfg)
+{
+ g_assert (cfg->gshared);
+
+ mono_create_rgctx_var (cfg);
return cfg->rgctx_var;
}
}
}
-static void
-emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
+static MonoInst*
+mono_create_fast_tls_getter (MonoCompile *cfg, MonoTlsKey key)
+{
+ int tls_offset = mono_tls_get_tls_offset (key);
+
+ if (cfg->compile_aot)
+ return NULL;
+
+ if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
+ MonoInst *ins;
+ MONO_INST_NEW (cfg, ins, OP_TLS_GET);
+ ins->dreg = mono_alloc_preg (cfg);
+ ins->inst_offset = tls_offset;
+ return ins;
+ }
+ return NULL;
+}
+
+static MonoInst*
+mono_create_fast_tls_setter (MonoCompile *cfg, MonoInst* value, MonoTlsKey key)
+{
+ int tls_offset = mono_tls_get_tls_offset (key);
+
+ if (cfg->compile_aot)
+ return NULL;
+
+ if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
+ MonoInst *ins;
+ MONO_INST_NEW (cfg, ins, OP_TLS_SET);
+ ins->sreg1 = value->dreg;
+ ins->inst_offset = tls_offset;
+ return ins;
+ }
+ return NULL;
+}
+
+
+MonoInst*
+mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
{
- MonoInst *ins, *c;
+ MonoInst *fast_tls = NULL;
+
+ if (!mini_get_debug_options ()->use_fallback_tls)
+ fast_tls = mono_create_fast_tls_getter (cfg, key);
+
+ if (fast_tls) {
+ MONO_ADD_INS (cfg->cbb, fast_tls);
+ return fast_tls;
+ }
if (cfg->compile_aot) {
- EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
- MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
- ins->sreg1 = sreg1;
- ins->sreg2 = c->dreg;
- MONO_ADD_INS (cfg->cbb, ins);
+ MonoInst *addr;
+ /*
+ * tls getters are critical pieces of code and we don't want to resolve them
+ * through the standard plt/tramp mechanism since we might expose ourselves
+ * to crashes and infinite recursions.
+ */
+ EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GET_TLS_TRAMP, (void*)key);
+ return mono_emit_calli (cfg, helper_sig_get_tls_tramp, NULL, addr, NULL, NULL);
} else {
- MONO_INST_NEW (cfg, ins, OP_TLS_SET);
- ins->sreg1 = sreg1;
- ins->inst_offset = mini_get_tls_offset (tls_key);
- MONO_ADD_INS (cfg->cbb, ins);
+ gpointer getter = mono_tls_get_tls_getter (key, FALSE);
+ return mono_emit_jit_icall (cfg, getter, NULL);
+ }
+}
+
+static MonoInst*
+mono_create_tls_set (MonoCompile *cfg, MonoInst *value, MonoTlsKey key)
+{
+ MonoInst *fast_tls = NULL;
+
+ if (!mini_get_debug_options ()->use_fallback_tls)
+ fast_tls = mono_create_fast_tls_setter (cfg, value, key);
+
+ if (fast_tls) {
+ MONO_ADD_INS (cfg->cbb, fast_tls);
+ return fast_tls;
+ }
+
+ if (cfg->compile_aot) {
+ MonoInst *addr;
+ EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_SET_TLS_TRAMP, (void*)key);
+ return mono_emit_calli (cfg, helper_sig_set_tls_tramp, &value, addr, NULL, NULL);
+ } else {
+ gpointer setter = mono_tls_get_tls_setter (key, FALSE);
+ return mono_emit_jit_icall (cfg, setter, &value);
}
}
* lmf->prev_lmf = *lmf_addr
* *lmf_addr = lmf
*/
- int lmf_reg, prev_lmf_reg;
MonoInst *ins, *lmf_ins;
if (!cfg->lmf_ir)
return;
- if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
- /* Load current lmf */
- lmf_ins = mono_get_lmf_intrinsic (cfg);
- g_assert (lmf_ins);
- MONO_ADD_INS (cfg->cbb, lmf_ins);
- EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
- lmf_reg = ins->dreg;
- /* Save previous_lmf */
- EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
- /* Set new LMF */
- emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
- } else {
- /*
- * Store lmf_addr in a variable, so it can be allocated to a global register.
- */
- if (!cfg->lmf_addr_var)
- cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ int lmf_reg, prev_lmf_reg;
+ /*
+ * Store lmf_addr in a variable, so it can be allocated to a global register.
+ */
+ if (!cfg->lmf_addr_var)
+ cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
#ifdef HOST_WIN32
- ins = mono_get_jit_tls_intrinsic (cfg);
- if (ins) {
- int jit_tls_dreg = ins->dreg;
-
- MONO_ADD_INS (cfg->cbb, ins);
- lmf_reg = alloc_preg (cfg);
- EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
- } else {
- lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
- }
-#else
- lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
- if (lmf_ins) {
- MONO_ADD_INS (cfg->cbb, lmf_ins);
- } else {
-#ifdef TARGET_IOS
- MonoInst *args [16], *jit_tls_ins, *ins;
-
- /* Inline mono_get_lmf_addr () */
- /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
+ ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
+ g_assert (ins);
+ int jit_tls_dreg = ins->dreg;
- /* Load mono_jit_tls_id */
- if (cfg->compile_aot)
- EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
- else
- EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
- /* call pthread_getspecific () */
- jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
- /* lmf_addr = &jit_tls->lmf */
- EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
- lmf_ins = ins;
+ lmf_reg = alloc_preg (cfg);
+ EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
#else
- lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
-#endif
- }
+ lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
+ g_assert (lmf_ins);
#endif
- lmf_ins->dreg = cfg->lmf_addr_var->dreg;
+ lmf_ins->dreg = cfg->lmf_addr_var->dreg;
- EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
- lmf_reg = ins->dreg;
+ EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
+ lmf_reg = ins->dreg;
- prev_lmf_reg = alloc_preg (cfg);
- /* Save previous_lmf */
- EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
- EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
- /* Set new lmf */
- EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
- }
+ prev_lmf_reg = alloc_preg (cfg);
+ /* Save previous_lmf */
+ EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
+ EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
+ /* Set new lmf */
+ EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
}
/*
static void
emit_pop_lmf (MonoCompile *cfg)
{
- int lmf_reg, lmf_addr_reg, prev_lmf_reg;
+ int lmf_reg, lmf_addr_reg;
MonoInst *ins;
if (!cfg->lmf_ir)
EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
lmf_reg = ins->dreg;
- if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
- /* Load previous_lmf */
- prev_lmf_reg = alloc_preg (cfg);
- EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
- /* Set new LMF */
- emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
- } else {
- /*
- * Emit IR to pop the LMF:
- * *(lmf->lmf_addr) = lmf->prev_lmf
- */
- /* This could be called before emit_push_lmf () */
- if (!cfg->lmf_addr_var)
- cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- lmf_addr_reg = cfg->lmf_addr_var->dreg;
+ int prev_lmf_reg;
+ /*
+ * Emit IR to pop the LMF:
+ * *(lmf->lmf_addr) = lmf->prev_lmf
+ */
+ /* This could be called before emit_push_lmf () */
+ if (!cfg->lmf_addr_var)
+ cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ lmf_addr_reg = cfg->lmf_addr_var->dreg;
- prev_lmf_reg = alloc_preg (cfg);
- EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
- EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
- }
+ prev_lmf_reg = alloc_preg (cfg);
+ EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
+ EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
}
static void
static gboolean
direct_icalls_enabled (MonoCompile *cfg)
{
+ return FALSE;
+
/* LLVM on amd64 can't handle calls to non-32 bit addresses */
#ifdef TARGET_AMD64
if (cfg->compile_llvm && !cfg->llvm_only)
static void
-emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
+emit_method_access_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
{
MonoInst *args [16];
- args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
- args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
+ args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (caller), caller, MONO_RGCTX_INFO_METHOD);
+ args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (callee), callee, MONO_RGCTX_INFO_METHOD);
mono_emit_jit_icall (cfg, mono_throw_method_access, args);
}
wbarrier->sreg1 = ptr->dreg;
wbarrier->sreg2 = value->dreg;
MONO_ADD_INS (cfg->cbb, wbarrier);
- } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
+ } else if (card_table) {
int offset_reg = alloc_preg (cfg);
int card_reg;
MonoInst *ins;
+ /*
+ * We emit a fast light weight write barrier. This always marks cards as in the concurrent
+ * collector case, so, for the serial collector, it might slightly slow down nursery
+ * collections. We also expect that the host system and the target system have the same card
+ * table configuration, which is the case if they have the same pointer size.
+ */
+
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
if (card_table_mask)
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
mrgctx_loc = mono_get_vtable_var (cfg);
EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
+ return mrgctx_var;
+ } else if (MONO_CLASS_IS_INTERFACE (cfg->method->klass)) {
+ MonoInst *mrgctx_loc, *mrgctx_var;
+
+ /* Default interface methods need an mrgctx since the vtabke at runtime points at an implementing class */
+ mrgctx_loc = mono_get_vtable_var (cfg);
+ EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
+
+ g_assert (mono_method_needs_static_rgctx_invoke (cfg->method, TRUE));
+
return mrgctx_var;
} else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
MonoInst *vtable_loc, *vtable_var;
ins->sreg1 = vtable_arg->dreg;
MONO_ADD_INS (cfg->cbb, ins);
} else {
- static int byte_offset = -1;
- static guint8 bitmask;
- int bits_reg, inited_reg;
+ int inited_reg;
MonoBasicBlock *inited_bb;
MonoInst *args [16];
- if (byte_offset < 0)
- mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
-
- bits_reg = alloc_ireg (cfg);
inited_reg = alloc_ireg (cfg);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, inited_reg, vtable_arg->dreg, MONO_STRUCT_OFFSET (MonoVTable, initialized));
NEW_BBLOCK (cfg, inited_bb);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
}
- tls_get = mono_get_jit_tls_intrinsic (cfg);
+ tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
if (!tls_get) {
fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
exit (1);
}
- MONO_ADD_INS (cfg->cbb, tls_get);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
{
/* Reset the variables holding the cast details */
if (mini_get_debug_options ()->better_cast_details) {
- MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
-
- MONO_ADD_INS (cfg->cbb, tls_get);
+ MonoInst *tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
/* It is enough to reset the from field */
MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
}
* pack the arguments into an array, and do the rest of the work in in an icall.
*/
if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
- (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (fsig->ret)) &&
+ (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret)) || mini_is_gsharedvt_type (fsig->ret)) &&
(fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) {
MonoInst *args [16];
if (mini_is_gsharedvt_type (fsig->ret)) {
ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
- } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
+ } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret))) {
MonoInst *add;
/* Unbox */
/* also consider num_locals? */
/* Do the size check early to avoid creating vtables */
if (!inline_limit_inited) {
- if (g_getenv ("MONO_INLINELIMIT"))
- inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
- else
+ char *inlinelimit;
+ if ((inlinelimit = g_getenv ("MONO_INLINELIMIT"))) {
+ inline_limit = atoi (inlinelimit);
+ g_free (inlinelimit);
+ } else
inline_limit = INLINE_LENGTH_LIMIT;
inline_limit_inited = TRUE;
}
#if SIZEOF_REGISTER == 8
/* The array reg is 64 bits but the index reg is only 32 */
if (COMPILE_LLVM (cfg)) {
- /* Not needed */
+ /*
+ * abcrem can't handle the OP_SEXT_I4, so add this after abcrem,
+ * during OP_BOUNDS_CHECK decomposition, and in the implementation
+ * of OP_X86_LEA for llvm.
+ */
index2_reg = index_reg;
} else {
index2_reg = alloc_preg (cfg);
/**
* mono_set_break_policy:
- * policy_callback: the new callback function
+ * \param policy_callback the new callback function
*
* Allow embedders to decide wherther to actually obey breakpoint instructions
- * (both break IL instructions and Debugger.Break () method calls), for example
+ * (both break IL instructions and \c Debugger.Break method calls), for example
* to not allow an app to be aborted by a perfectly valid IL opcode when executing
* untrusted or semi-trusted code.
*
- * @policy_callback will be called every time a break point instruction needs to
- * be inserted with the method argument being the method that calls Debugger.Break()
- * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
+ * \p policy_callback will be called every time a break point instruction needs to
+ * be inserted with the method argument being the method that calls \c Debugger.Break
+ * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
* if it wants the breakpoint to not be effective in the given method.
- * #MONO_BREAK_POLICY_ALWAYS is the default.
+ * \c MONO_BREAK_POLICY_ALWAYS is the default.
*/
void
mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
MonoInst *ins = NULL;
-
- MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
+ MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
if (cmethod->klass == mono_defaults.string_class) {
if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
} else if (cmethod->klass == runtime_helpers_class) {
if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
+ return ins;
+ } else if (strcmp (cmethod->name, "IsReferenceOrContainsReferences") == 0 && fsig->param_count == 0) {
+ MonoGenericContext *ctx = mono_method_get_context (cmethod);
+ g_assert (ctx);
+ g_assert (ctx->method_inst);
+ g_assert (ctx->method_inst->type_argc == 1);
+ MonoType *t = mini_get_underlying_type (ctx->method_inst->type_argv [0]);
+ MonoClass *klass = mono_class_from_mono_type (t);
+
+ ins = NULL;
+
+ mono_class_init (klass);
+ if (MONO_TYPE_IS_REFERENCE (t))
+ EMIT_NEW_ICONST (cfg, ins, 1);
+ else if (MONO_TYPE_IS_PRIMITIVE (t))
+ EMIT_NEW_ICONST (cfg, ins, 0);
+ else if (cfg->gshared && (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (t))
+ EMIT_NEW_ICONST (cfg, ins, 1);
+ else if (!cfg->gshared || !mini_class_check_context_used (cfg, klass))
+ EMIT_NEW_ICONST (cfg, ins, klass->has_references ? 1 : 0);
+ else {
+ g_assert (cfg->gshared);
+
+ int context_used = mini_class_check_context_used (cfg, klass);
+
+ /* This returns 1 or 2 */
+ MonoInst *info = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS);
+ int dreg = alloc_ireg (cfg);
+ EMIT_NEW_BIALU_IMM (cfg, ins, OP_ISUB_IMM, dreg, info->dreg, 1);
+ }
+
return ins;
} else
return NULL;
ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
- ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
+ ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_internal : (gpointer)mono_monitor_enter_internal, args);
MONO_START_BB (cfg, end_bb);
return ins;
}
* Get rid of the begin and end bblocks if possible to aid local
* optimizations.
*/
- mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
+ if (prev_cbb->out_count == 1)
+ mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
{
MonoMethod *method;
- mono_error_init (error);
+ error_init (error);
if (m->wrapper_type != MONO_WRAPPER_NONE) {
method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
{
MonoMethodSignature *fsig;
- mono_error_init (error);
+ error_init (error);
if (method->wrapper_type != MONO_WRAPPER_NONE) {
fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
} else {
return NULL;
if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
return NULL;
- switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
- case MONO_TYPE_BOOLEAN:
+ switch (mini_get_underlying_type (&klass->byval_arg)->type) {
case MONO_TYPE_I1:
case MONO_TYPE_U1:
size = 1; break;
/* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
#if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
- case MONO_TYPE_CHAR:
case MONO_TYPE_I2:
case MONO_TYPE_U2:
size = 2; break;
gboolean variant_iface = FALSE;
guint32 slot;
int offset;
+ gboolean special_array_interface = cmethod->klass->is_array_special_interface;
/*
* In llvm-only mode, vtables contain function descriptors instead of
return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
}
- if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
+ if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt && !special_array_interface) {
/*
* A simple interface call
*
return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
}
- if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
+ if ((fsig->generic_param_count || variant_iface || special_array_interface) && !is_gsharedvt) {
/*
* This is similar to the interface case, the vtable slot points to an imt thunk which is
* dynamically extended as more instantiations are discovered.
mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
}
g_free (sps);
+
+ MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
+ if (asyncMethod) {
+ for (i = 0; asyncMethod != NULL && i < asyncMethod->num_awaits; i++)
+ {
+ mono_bitset_set_fast (seq_point_locs, asyncMethod->resume_offsets[i]);
+ mono_bitset_set_fast (seq_point_locs, asyncMethod->yield_offsets[i]);
+ }
+ mono_debug_free_method_async_debug_info (asyncMethod);
+ }
} else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
/* Methods without line number info like auto-generated property accessors */
seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
CHECK_CFG_ERROR;
}
}
+
+ if (constrained_class->enumtype && !strcmp (cmethod->name, "GetHashCode")) {
+ /* Use the corresponding method from the base type to avoid boxing */
+ MonoType *base_type = mono_class_enum_basetype (constrained_class);
+ g_assert (base_type);
+ constrained_class = mono_class_from_mono_type (base_type);
+ cmethod = mono_class_get_method_from_name (constrained_class, cmethod->name, 0);
+ g_assert (cmethod);
+ }
}
if (!dont_verify && !cfg->skip_visibility) {
* request a generic sharing context.
*/
if (context_used &&
- ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
+ ((cfg->method->flags & METHOD_ATTRIBUTE_STATIC) || cfg->method->klass->valuetype))
mono_get_vtable_var (cfg);
}
is_special_static = mono_class_field_is_special_static (field);
if (is_special_static && ((gsize)addr & 0x80000000) == 0)
- thread_ins = mono_get_thread_intrinsic (cfg);
+ thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
else
thread_ins = NULL;
guint32 offset;
int idx, static_data_reg, array_reg, dreg;
- GSHAREDVT_FAILURE (op);
+ if (context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))
+ GSHAREDVT_FAILURE (op);
- MONO_ADD_INS (cfg->cbb, thread_ins);
static_data_reg = alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
+ if (klass->byval_arg.type == MONO_TYPE_VOID)
+ UNVERIFIED;
context_used = mini_class_check_context_used (cfg, klass);
tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
} else if (cfg->compile_aot) {
if (method->wrapper_type) {
- mono_error_init (&error); //got to do it since there are multiple conditionals below
+ error_init (&error); //got to do it since there are multiple conditionals below
if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
/* Special case for static synchronized wrappers */
EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
g_assert (key < TLS_KEY_NUM);
ins = mono_create_tls_get (cfg, key);
- if (!ins) {
- if (cfg->compile_aot) {
- DISABLE_AOT (cfg);
- MONO_INST_NEW (cfg, ins, OP_TLS_GET);
- ins->dreg = alloc_preg (cfg);
- ins->type = STACK_PTR;
- } else {
- g_assert_not_reached ();
- }
- }
+ g_assert (ins);
ins->type = STACK_PTR;
- MONO_ADD_INS (cfg->cbb, ins);
*sp++ = ins;
ip += 6;
break;
EMIT_NEW_PCONST (cfg, ins, NULL);
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
- ad_ins = mono_get_domain_intrinsic (cfg);
- jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
+ ad_ins = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
+ jit_tls_ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
- if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
+ if (ad_ins && jit_tls_ins) {
NEW_BBLOCK (cfg, next_bb);
NEW_BBLOCK (cfg, call_bb);
} else {
EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
}
- MONO_ADD_INS (cfg->cbb, ad_ins);
MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
- MONO_ADD_INS (cfg->cbb, jit_tls_ins);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
ins->type = STACK_I4;
MONO_ADD_INS (cfg->cbb, ins);
+ ip += 2;
+ *sp++ = ins;
+ break;
+ case CEE_MONO_GET_RGCTX_ARG:
+ CHECK_OPSIZE (2);
+ CHECK_STACK_OVF (1);
+
+ mono_create_rgctx_var (cfg);
+
+ MONO_INST_NEW (cfg, ins, OP_MOVE);
+ ins->dreg = alloc_dreg (cfg, STACK_PTR);
+ ins->sreg1 = cfg->rgctx_var->dreg;
+ ins->type = STACK_PTR;
+ MONO_ADD_INS (cfg->cbb, ins);
+
ip += 2;
*sp++ = ins;
break;
cfg->cbb = init_localsbb;
- if ((get_domain = mono_get_domain_intrinsic (cfg))) {
- MONO_ADD_INS (cfg->cbb, get_domain);
- } else {
- get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
- }
+ get_domain = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
MONO_ADD_INS (cfg->cbb, store);
}
int orig_next_vreg;
guint32 *vreg_to_lvreg;
guint32 *lvregs;
- guint32 i, lvregs_len;
+ guint32 i, lvregs_len, lvregs_size;
gboolean dest_has_lvreg = FALSE;
MonoStackType stacktypes [128];
MonoInst **live_range_start, **live_range_end;
*/
orig_next_vreg = cfg->next_vreg;
vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
- lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
+ lvregs_size = 1024;
+ lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * lvregs_size);
lvregs_len = 0;
/*
}
g_assert (sreg != -1);
vreg_to_lvreg [var->dreg] = sreg;
- g_assert (lvregs_len < 1024);
+ if (lvregs_len >= lvregs_size) {
+ guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
+ memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
+ lvregs = new_lvregs;
+ lvregs_size *= 2;
+ }
lvregs [lvregs_len ++] = var->dreg;
}
}
if (dest_has_lvreg) {
g_assert (ins->dreg != -1);
vreg_to_lvreg [prev_dreg] = ins->dreg;
- g_assert (lvregs_len < 1024);
+ if (lvregs_len >= lvregs_size) {
+ guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
+ memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
+ lvregs = new_lvregs;
+ lvregs_size *= 2;
+ }
lvregs [lvregs_len ++] = prev_dreg;
dest_has_lvreg = FALSE;
}
#else /* !DISABLE_JIT */
-MONO_EMPTY_SOURCE_FILE (method_to_ir);
+void
+mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
+{
+}
#endif /* !DISABLE_JIT */