}
static void
-emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc)
+emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
{
MonoInst *ins;
if (cfg->gen_seq_points && cfg->method == method) {
NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
+ if (nonempty_stack)
+ ins->flags |= MONO_INST_NONEMPTY_STACK;
MONO_ADD_INS (cfg->cbb, ins);
}
}
static void
-save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
+save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
{
if (mini_get_debug_options ()->better_cast_details) {
int to_klass_reg = alloc_preg (cfg);
int vtable_reg = alloc_preg (cfg);
int klass_reg = alloc_preg (cfg);
- MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
+ MonoBasicBlock *is_null_bb = NULL;
+ MonoInst *tls_get;
+
+ if (null_check) {
+ NEW_BBLOCK (cfg, is_null_bb);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
+ }
+
+ tls_get = mono_get_jit_tls_intrinsic (cfg);
if (!tls_get) {
fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
exit (1);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
+
+ if (null_check) {
+ MONO_START_BB (cfg, is_null_bb);
+ if (out_bblock)
+ *out_bblock = cfg->cbb;
+ }
}
}
context_used = mini_class_check_context_used (cfg, array_class);
- save_cast_details (cfg, array_class, obj->dreg);
+ save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
} else {
- save_cast_details (cfg, klass->element_class, obj_reg);
+ save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
mini_emit_class_check (cfg, eclass_reg, klass->element_class);
reset_cast_details (cfg);
}
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
- save_cast_details (cfg, klass, obj_reg);
+ save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
- save_cast_details (cfg, klass, obj_reg);
+ save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
#ifndef DISABLE_REMOTING
}
static gboolean
-mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
+mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
{
- if (vtable->initialized && !cfg->compile_aot)
- return FALSE;
+ if (!cfg->compile_aot) {
+ g_assert (vtable);
+ if (vtable->initialized)
+ return FALSE;
+ }
- if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
+ if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
return FALSE;
- if (!mono_class_needs_cctor_run (vtable->klass, method))
+ if (!mono_class_needs_cctor_run (klass, method))
return FALSE;
- if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
+ if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
/* The initialization is already done before the method is called */
return FALSE;
* all inputs:
* http://everything2.com/?node_id=1051618
*/
+ } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") || !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) && !strcmp (cmethod->klass->name, "Selector") && !strcmp (cmethod->name, "GetHandle") && cfg->compile_aot && (args [0]->opcode == OP_GOT_ENTRY || args[0]->opcode == OP_AOTCONST)) {
+#ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
+ MonoInst *pi;
+ MonoJumpInfoToken *ji;
+ MonoString *s;
+
+ cfg->disable_llvm = TRUE;
+
+ if (args [0]->opcode == OP_GOT_ENTRY) {
+ pi = args [0]->inst_p1;
+ g_assert (pi->opcode == OP_PATCH_INFO);
+ g_assert ((int)pi->inst_p1 == MONO_PATCH_INFO_LDSTR);
+ ji = pi->inst_p0;
+ } else {
+ g_assert ((int)args [0]->inst_p1 == MONO_PATCH_INFO_LDSTR);
+ ji = args [0]->inst_p0;
+ }
+
+ NULLIFY_INS (args [0]);
+
+ // FIXME: Ugly
+ s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
+ 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);
+ MONO_ADD_INS (cfg->cbb, ins);
+ return ins;
+#endif
}
#ifdef MONO_ARCH_SIMD_INTRINSICS
check_inline_called_method_name_limit (MonoMethod *called_method)
{
int strncmp_result;
- static char *limit = NULL;
+ static const char *limit = NULL;
if (limit == NULL) {
- char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
+ const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
if (limit_string != NULL)
limit = limit_string;
else
- limit = (char *) "";
+ limit = "";
}
if (limit [0] != '\0') {
check_inline_caller_method_name_limit (MonoMethod *caller_method)
{
int strncmp_result;
- static char *limit = NULL;
+ static const char *limit = NULL;
if (limit == NULL) {
- char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
+ const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
if (limit_string != NULL) {
limit = limit_string;
} else {
- limit = (char *) "";
+ limit = "";
}
}
}
}
+ CHECK_CFG_EXCEPTION;
+
if (header->code_size == 0)
UNVERIFIED;
// FIXME: Enable this
//if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
+ if (sp != stack_start)
+ ins->flags |= MONO_INST_NONEMPTY_STACK;
MONO_ADD_INS (cfg->cbb, ins);
if (sym_seq_points)
if (fsig->pinvoke) {
MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
- check_for_pending_exc, FALSE);
+ check_for_pending_exc, cfg->compile_aot);
fsig = mono_method_signature (wrapper);
} else if (constrained_call) {
fsig = mono_method_signature (cmethod);
mono_save_token_info (cfg, image, token, cil_method);
- if (!MONO_TYPE_IS_VOID (fsig->ret) && !sym_seq_points) {
+ if (!MONO_TYPE_IS_VOID (fsig->ret)) {
/*
* Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
* foo (bar (), baz ())
* int i = foo ();
*/
/* Special case a few common successor opcodes */
- if (!(ip + 5 < end && ip [5] == CEE_POP))
+ if (!(ip + 5 < end && (ip [5] == CEE_POP || ip [5] == CEE_NOP)) && !(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
need_seq_point = TRUE;
}
*/
if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
/* The 'Own method' case below */
+ } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
+ /* 'The type parameter is instantiated as a reference type' case below. */
} else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!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) || mini_is_gsharedvt_type (cfg, fsig->ret)) &&
(fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || mini_is_gsharedvt_type (cfg, fsig->params [0]))))) {
ins_flag = 0;
constrained_call = NULL;
if (need_seq_point)
- emit_seq_point (cfg, method, ip, FALSE);
+ emit_seq_point (cfg, method, ip, FALSE, TRUE);
break;
}
case CEE_RET:
alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
*sp = alloc;
} else {
- MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+ MonoVTable *vtable = NULL;
+ if (!cfg->compile_aot)
+ vtable = mono_class_vtable (cfg->domain, cmethod->klass);
CHECK_TYPELOAD (cmethod->klass);
/*
* call in mono_jit_runtime_invoke () can abort the finalizer thread.
* As a workaround, we call class cctors before allocating objects.
*/
- if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
- mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
+ if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
+ mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
if (cfg->verbose_level > 2)
printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
- class_inits = g_slist_prepend (class_inits, vtable);
+ class_inits = g_slist_prepend (class_inits, cmethod->klass);
}
alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
/*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
- save_cast_details (cfg, klass, sp [0]->dreg);
+
+ save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
*sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
reset_cast_details (cfg);
ip += 5;
mono_castclass = mono_marshal_get_castclass (klass);
iargs [0] = sp [0];
- save_cast_details (cfg, klass, sp [0]->dreg);
+ save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass),
iargs, ip, cfg->real_offset, dont_inline, TRUE);
reset_cast_details (cfg);
EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
} else {
- MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+ MonoVTable *vtable = NULL;
+ if (!cfg->compile_aot)
+ vtable = mono_class_vtable (cfg->domain, klass);
CHECK_TYPELOAD (klass);
+
if (!addr) {
- if (mini_field_access_needs_cctor_run (cfg, method, vtable)) {
- if (!(g_slist_find (class_inits, vtable))) {
- mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
+ if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
+ if (!(g_slist_find (class_inits, klass))) {
+ mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
if (cfg->verbose_level > 2)
printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
- class_inits = g_slist_prepend (class_inits, vtable);
+ class_inits = g_slist_prepend (class_inits, klass);
}
} else {
if (cfg->run_cctors) {
/* This makes so that inline cannot trigger */
/* .cctors: too many apps depend on them */
/* running with a specific order... */
+ g_assert (vtable);
if (! vtable->initialized)
INLINE_FAILURE ("class init");
ex = mono_runtime_class_init_full (vtable, FALSE);
}
}
}
- addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
-
if (cfg->compile_aot)
EMIT_NEW_SFLDACONST (cfg, ins, field);
- else
+ else {
+ g_assert (vtable);
+ addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
EMIT_NEW_PCONST (cfg, ins, addr);
+ }
} else {
MonoInst *iargs [1];
EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
case CEE_ENDFINALLY:
/* mono_save_seq_point_info () depends on this */
if (sp != stack_start)
- emit_seq_point (cfg, method, ip, FALSE);
+ emit_seq_point (cfg, method, ip, FALSE, FALSE);
MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
MONO_ADD_INS (bblock, ins);
ip++;
bblock->out_of_line = TRUE;
ip += 2;
break;
- case CEE_MONO_TLS:
+ case CEE_MONO_TLS: {
+ int key;
+
CHECK_STACK_OVF (1);
CHECK_OPSIZE (6);
- MONO_INST_NEW (cfg, ins, OP_TLS_GET);
- ins->dreg = alloc_preg (cfg);
- ins->inst_offset = (gint32)read32 (ip + 2);
+ key = (gint32)read32 (ip + 2);
+ g_assert (key < TLS_KEY_NUM);
+
+ ins = mono_create_tls_get (cfg, key);
+ if (!ins) {
+ if (cfg->compile_aot) {
+ cfg->disable_aot = TRUE;
+ MONO_INST_NEW (cfg, ins, OP_TLS_GET);
+ ins->dreg = alloc_preg (cfg);
+ ins->type = STACK_PTR;
+ } else {
+ g_assert_not_reached ();
+ }
+ }
ins->type = STACK_PTR;
MONO_ADD_INS (bblock, ins);
*sp++ = ins;
ip += 6;
break;
+ }
case CEE_MONO_DYN_CALL: {
MonoCallInst *call;