#include <mono/utils/mono-error-internals.h>
#include <mono/metadata/mono-basic-block.h>
#include <mono/metadata/reflection-internals.h>
+#include <mono/utils/mono-threads-coop.h>
#include "trace.h"
if (cfg->exception_type != MONO_EXCEPTION_NONE) \
goto exception_exit; \
} while (0)
-#define METHOD_ACCESS_FAILURE(method, cmethod) do { \
- method_access_failure ((cfg), (method), (cmethod)); \
- goto exception_exit; \
- } while (0)
#define FIELD_ACCESS_FAILURE(method, field) do { \
field_access_failure ((cfg), (method), (field)); \
goto exception_exit; \
G_BREAKPOINT ();
}
-static MONO_NEVER_INLINE void
-method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
-{
- char *method_fname = mono_method_full_name (method, TRUE);
- char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
- mono_error_set_generic_error (&cfg->error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
- g_free (method_fname);
- g_free (cil_method_fname);
-}
-
static MONO_NEVER_INLINE void
field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
{
return -1;
}
+static gboolean
+ip_in_finally_clause (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_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
+ continue;
+
+ if (MONO_OFFSET_IN_HANDLER (clause, offset))
+ return TRUE;
+ }
+ return FALSE;
+}
+
static GList*
mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
{
if (target->byref) {
/* FIXME: check that the pointed to types match */
if (arg->type == STACK_MP) {
- if (cfg->verbose_level) printf ("ok\n");
/* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
return ins;
}
+
+static void
+emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
+{
+ 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);
+
+ mono_emit_jit_icall (cfg, mono_throw_method_access, args);
+}
+
static MonoMethod*
get_memcpy_method (void)
{
RGCTX. */
addr = emit_get_rgctx_method (cfg, context_used, method,
MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
- if (cfg->llvm_only && cfg->gsharedvt) {
+ if (cfg->llvm_only) {
+ cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
} else {
rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
#define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+static MonoInst*
+emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
+{
+ MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
+ return mono_emit_method_call (cfg, mono_isinst, args, NULL);
+}
+
static MonoInst*
emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
{
- MonoMethod *mono_castclass;
+ MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
MonoInst *res;
- mono_castclass = mono_marshal_get_castclass_with_cache ();
-
save_cast_details (cfg, klass, args [0]->dreg, TRUE);
res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
reset_cast_details (cfg);
return (cfg->method_index << 16) | cfg->castclass_cache_index;
}
+
+static MonoInst*
+emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
+{
+ MonoInst *args [3];
+ int idx;
+
+ args [0] = obj; /* obj */
+ EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
+
+ idx = get_castclass_cache_idx (cfg); /* inline cache*/
+ args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
+
+ return emit_isinst_with_cache (cfg, klass, args);
+}
+
static MonoInst*
emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
{
* Returns NULL and set the cfg exception on error.
*/
static MonoInst*
-handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
+handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
{
MonoBasicBlock *is_null_bb;
int obj_reg = src->dreg;
int vtable_reg = alloc_preg (cfg);
- int context_used;
- MonoInst *klass_inst = NULL, *res;
-
- context_used = mini_class_check_context_used (cfg, klass);
-
- if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
- res = emit_castclass_with_cache_nonshared (cfg, src, klass);
- (*inline_costs) += 2;
- return res;
- } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
- MonoMethod *mono_castclass;
- MonoInst *iargs [1];
- int costs;
-
- mono_castclass = mono_marshal_get_castclass (klass);
- iargs [0] = src;
-
- save_cast_details (cfg, klass, src->dreg, TRUE);
- costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass),
- iargs, ip, cfg->real_offset, TRUE);
- reset_cast_details (cfg);
- CHECK_CFG_EXCEPTION;
- g_assert (costs > 0);
-
- cfg->real_offset += 5;
-
- (*inline_costs) += costs;
+ MonoInst *klass_inst = NULL;
+ if (src->opcode == OP_PCONST && src->inst_p0 == 0)
return src;
- }
if (context_used) {
MonoInst *args [3];
- if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
+ if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
MonoInst *cache_ins;
cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
reset_cast_details (cfg);
return src;
-
-exception_exit:
- return NULL;
}
/*
MonoInst *args [3];
if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
- MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
- MonoInst *cache_ins;
+ MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
- cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
-
- /* obj */
- args [0] = src;
+ args [0] = src; /* obj */
/* klass - it's the second element of the cache entry*/
EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
- /* cache */
- args [2] = cache_ins;
-
- return mono_emit_method_call (cfg, mono_isinst, args, NULL);
+ args [2] = cache_ins; /* cache */
+ return emit_isinst_with_cache (cfg, klass, args);
}
klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
if (opcode && fsig->param_count == 1) {
MONO_INST_NEW (cfg, ins, opcode);
ins->type = STACK_R8;
- ins->dreg = mono_alloc_freg (cfg);
+ ins->dreg = mono_alloc_dreg (cfg, ins->type);
ins->sreg1 = args [0]->dreg;
MONO_ADD_INS (cfg->cbb, ins);
}
if (opcode && fsig->param_count == 2) {
MONO_INST_NEW (cfg, ins, opcode);
ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
- ins->dreg = mono_alloc_ireg (cfg);
+ ins->dreg = mono_alloc_dreg (cfg, ins->type);
ins->sreg1 = args [0]->dreg;
ins->sreg2 = args [1]->dreg;
MONO_ADD_INS (cfg->cbb, ins);
!strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
!strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
!strcmp (cmethod->klass->name, "Selector")) ||
- (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
+ ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
+ !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
!strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
!strcmp (cmethod->klass->name, "Selector"))
) {
- if (cfg->backend->have_objc_get_selector &&
+ if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
!strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
(args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
- cfg->compile_aot && !cfg->llvm_only) {
+ cfg->compile_aot) {
MonoInst *pi;
MonoJumpInfoToken *ji;
- MonoString *s;
-
- // FIXME: llvmonly
-
- cfg->exception_message = g_strdup ("GetHandle");
- cfg->disable_llvm = TRUE;
+ char *s;
if (args [0]->opcode == OP_GOT_ENTRY) {
pi = (MonoInst *)args [0]->inst_p1;
NULLIFY_INS (args [0]);
- // FIXME: Ugly
- s = mono_ldstr_checked (cfg->domain, ji->image, mono_metadata_token_index (ji->token), &cfg->error);
+ s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
return_val_if_nok (&cfg->error, NULL);
+
MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
ins->dreg = mono_alloc_ireg (cfg);
// FIXME: Leaks
- ins->inst_p0 = mono_string_to_utf8 (s);
+ ins->inst_p0 = s;
MONO_ADD_INS (cfg->cbb, ins);
return ins;
}
if (!header) {
mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
goto exception_exit;
+ } else {
+ cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
}
+
generic_container = mono_method_get_generic_container (method);
sig = mono_method_signature (method);
num_args = sig->hasthis + sig->param_count;
for (i = 0; i < n; ++i)
EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
+ if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
+ call->vret_var = cfg->vret_addr;
+
mono_arch_emit_call (cfg, call);
cfg->param_area = MAX(cfg->param_area, call->stack_usage);
MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
}
if (!mono_method_can_access_method (method_definition, target_method) &&
!mono_method_can_access_method (method, cil_method))
- METHOD_ACCESS_FAILURE (method, cil_method);
+ emit_method_access_failure (cfg, method, cil_method);
}
if (mono_security_core_clr_enabled ())
inline_costs += 10 * num_calls++;
+ /*
+ * Synchronized wrappers.
+ * Its hard to determine where to replace a method with its synchronized
+ * wrapper without causing an infinite recursion. The current solution is
+ * to add the synchronized wrapper in the trampolines, and to
+ * change the called method to a dummy wrapper, and resolve that wrapper
+ * to the real method in mono_jit_compile_method ().
+ */
+ if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
+ MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
+ if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
+ cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
+ }
+
/*
* Making generic calls out of gsharedvt methods.
* This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
}
}
- /*
- * Synchronized wrappers.
- * Its hard to determine where to replace a method with its synchronized
- * wrapper without causing an infinite recursion. The current solution is
- * to add the synchronized wrapper in the trampolines, and to
- * change the called method to a dummy wrapper, and resolve that wrapper
- * to the real method in mono_jit_compile_method ().
- */
- if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
- MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
- if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
- cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
- }
-
/*
* Virtual calls in llvm-only mode.
*/
break;
}
case CEE_CASTCLASS:
- CHECK_STACK (1);
- --sp;
- CHECK_OPSIZE (5);
- token = read32 (ip + 1);
- klass = mini_get_class (method, token, generic_context);
- CHECK_TYPELOAD (klass);
- if (sp [0]->type != STACK_OBJ)
- UNVERIFIED;
-
- ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
- CHECK_CFG_EXCEPTION;
-
- *sp ++ = ins;
- ip += 5;
- break;
case CEE_ISINST: {
CHECK_STACK (1);
--sp;
CHECK_TYPELOAD (klass);
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
-
- context_used = mini_class_check_context_used (cfg, klass);
-
- if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
- MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
- MonoInst *args [3];
- int idx;
-
- /* obj */
- args [0] = *sp;
-
- /* klass */
- EMIT_NEW_CLASSCONST (cfg, args [1], klass);
-
- /* inline cache*/
- idx = get_castclass_cache_idx (cfg);
- args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
-
- *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
- ip += 5;
- inline_costs += 2;
- } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
- MonoMethod *mono_isinst;
- MonoInst *iargs [1];
- int costs;
- mono_isinst = mono_marshal_get_isinst (klass);
- iargs [0] = sp [0];
-
- costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst),
- iargs, ip, cfg->real_offset, TRUE);
- CHECK_CFG_EXCEPTION;
- g_assert (costs > 0);
-
- ip += 5;
- cfg->real_offset += 5;
+ MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
+ ins->dreg = alloc_preg (cfg);
+ ins->sreg1 = (*sp)->dreg;
+ ins->klass = klass;
+ ins->type = STACK_OBJ;
+ MONO_ADD_INS (cfg->cbb, ins);
- *sp++= iargs [0];
+ CHECK_CFG_EXCEPTION;
+ *sp++ = ins;
+ ip += 5;
- inline_costs += costs;
- }
- else {
- ins = handle_isinst (cfg, klass, *sp, context_used);
- CHECK_CFG_EXCEPTION;
- *sp ++ = ins;
- ip += 5;
- }
+ cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
break;
}
case CEE_UNBOX_ANY: {
res = handle_unbox_gsharedvt (cfg, klass, *sp);
inline_costs += 2;
} else if (generic_class_is_reference_type (cfg, klass)) {
- res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
- CHECK_CFG_EXCEPTION;
+ MONO_INST_NEW (cfg, res, OP_CASTCLASS);
+ res->dreg = alloc_preg (cfg);
+ res->sreg1 = (*sp)->dreg;
+ res->klass = klass;
+ res->type = STACK_OBJ;
+ MONO_ADD_INS (cfg->cbb, res);
+ cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
} else if (mono_class_is_nullable (klass)) {
res = handle_unbox_nullable (cfg, *sp, klass, context_used);
} else {
MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
+ if (ins_flag & MONO_INST_VOLATILE) {
+ /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
+ emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+ }
+
if (mini_is_gsharedvt_klass (klass)) {
MonoInst *offset_ins;
INLINE_FAILURE ("throw");
break;
case CEE_ENDFINALLY:
+ if (!ip_in_finally_clause (cfg, ip - header->code))
+ UNVERIFIED;
/* mono_save_seq_point_info () depends on this */
if (sp != stack_start)
emit_seq_point (cfg, method, ip, FALSE, FALSE);
ip += 6;
break;
}
+ case CEE_MONO_ATOMIC_STORE_I4: {
+ g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
+
+ CHECK_OPSIZE (6);
+ CHECK_STACK (2);
+ sp -= 2;
+
+ MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
+ ins->dreg = sp [0]->dreg;
+ ins->sreg1 = sp [1]->dreg;
+ ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ ip += 6;
+ break;
+ }
case CEE_MONO_JIT_ATTACH: {
MonoInst *args [16], *domain_ins;
MonoInst *ad_ins, *jit_tls_ins;
MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
- cfg->attach_cookie = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- cfg->attach_dummy = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ g_assert (!mono_threads_is_coop_enabled ());
- if (mono_threads_is_coop_enabled ()) {
- /* AOT code is only used in the root domain */
- EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
- EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
- ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
- MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
- } else {
- EMIT_NEW_PCONST (cfg, ins, NULL);
- MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
-
- ad_ins = mono_get_domain_intrinsic (cfg);
- jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
+ cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
- NEW_BBLOCK (cfg, next_bb);
- NEW_BBLOCK (cfg, call_bb);
+ EMIT_NEW_PCONST (cfg, ins, NULL);
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
- if (cfg->compile_aot) {
- /* AOT code is only used in the root domain */
- EMIT_NEW_PCONST (cfg, domain_ins, NULL);
- } 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);
+ ad_ins = mono_get_domain_intrinsic (cfg);
+ jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
- 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);
+ if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
+ NEW_BBLOCK (cfg, next_bb);
+ NEW_BBLOCK (cfg, call_bb);
- MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
- MONO_START_BB (cfg, call_bb);
+ if (cfg->compile_aot) {
+ /* AOT code is only used in the root domain */
+ EMIT_NEW_PCONST (cfg, domain_ins, NULL);
+ } 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);
- /* AOT code is only used in the root domain */
- EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
- EMIT_NEW_PCONST (cfg, args [1], NULL);
- ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
- MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
+ 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);
- if (next_bb)
- MONO_START_BB (cfg, next_bb);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
+ MONO_START_BB (cfg, call_bb);
}
+ /* AOT code is only used in the root domain */
+ EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
+ ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
+
+ if (next_bb)
+ MONO_START_BB (cfg, next_bb);
+
+
ip += 2;
break;
}
/* Restore the original domain */
dreg = alloc_ireg (cfg);
- EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->attach_cookie->dreg);
- EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
- mono_emit_jit_icall (cfg, mono_jit_thread_detach, args);
+ EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
+ mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
ip += 2;
break;
}
constrained_class = NULL;
break;
}
+ case CEE_MONO_LDDOMAIN:
+ CHECK_STACK_OVF (1);
+ EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
+ ip += 2;
+ *sp++ = ins;
+ break;
default:
g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
break;
cil_method = cmethod;
if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
- METHOD_ACCESS_FAILURE (method, cil_method);
+ emit_method_access_failure (cfg, method, cil_method);
if (mono_security_core_clr_enabled ())
ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
ip += 4;
inline_costs += 1;
break;
- case CEE_LOCALLOC:
+ case CEE_LOCALLOC: {
CHECK_STACK (1);
+ MonoBasicBlock *non_zero_bb, *end_bb;
+ int alloc_ptr = alloc_preg (cfg);
--sp;
if (sp != stack_start)
UNVERIFIED;
*/
INLINE_FAILURE("localloc");
+ NEW_BBLOCK (cfg, non_zero_bb);
+ NEW_BBLOCK (cfg, end_bb);
+
+ /* if size != zero */
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
+
+ //size is zero, so result is NULL
+ MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+
+ MONO_START_BB (cfg, non_zero_bb);
MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
- ins->dreg = alloc_preg (cfg);
+ ins->dreg = alloc_ptr;
ins->sreg1 = sp [0]->dreg;
ins->type = STACK_PTR;
MONO_ADD_INS (cfg->cbb, ins);
if (init_locals)
ins->flags |= MONO_INST_INIT;
+ MONO_START_BB (cfg, end_bb);
+ EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
+ ins->type = STACK_PTR;
+
*sp++ = ins;
ip += 2;
break;
+ }
case CEE_ENDFILTER: {
MonoExceptionClause *clause, *nearest;
int cc;
g_slist_free (class_inits);
mono_basic_block_free (original_bb);
cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
- cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
if (cfg->exception_type)
return -1;
else
g_free (live_range_end_bb);
}
+static void
+mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
+{
+ MonoInst *ret, *move, *source;
+ MonoClass *klass = ins->klass;
+ int context_used = mini_class_check_context_used (cfg, klass);
+ int is_isinst = ins->opcode == OP_ISINST;
+ g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
+ source = get_vreg_to_inst (cfg, ins->sreg1);
+ if (!source || source == (MonoInst *) -1)
+ source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
+ g_assert (source && source != (MonoInst *) -1);
+
+ MonoBasicBlock *first_bb;
+ NEW_BBLOCK (cfg, first_bb);
+ cfg->cbb = first_bb;
+
+ if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
+ if (is_isinst)
+ ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
+ else
+ ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
+ } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ MonoInst *iargs [1];
+ int costs;
+
+ iargs [0] = source;
+ if (is_isinst) {
+ MonoMethod *wrapper = mono_marshal_get_isinst (klass);
+ costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
+ } else {
+ MonoMethod *wrapper = mono_marshal_get_castclass (klass);
+ save_cast_details (cfg, klass, source->dreg, TRUE);
+ costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
+ reset_cast_details (cfg);
+ }
+ g_assert (costs > 0);
+ ret = iargs [0];
+ } else {
+ if (is_isinst)
+ ret = handle_isinst (cfg, klass, source, context_used);
+ else
+ ret = handle_castclass (cfg, klass, source, context_used);
+ }
+ EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
+
+ g_assert (cfg->cbb->code || first_bb->code);
+ MonoInst *prev = ins->prev;
+ mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
+}
+
+void
+mono_decompose_typechecks (MonoCompile *cfg)
+{
+ for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ MonoInst *ins;
+ MONO_BB_FOR_EACH_INS (bb, ins) {
+ switch (ins->opcode) {
+ case OP_ISINST:
+ case OP_CASTCLASS:
+ mono_decompose_typecheck (cfg, bb, ins);
+ break;
+ }
+ }
+ }
+}
+
+
/**
* FIXME:
* - use 'iadd' instead of 'int_add'