#include <mono/metadata/profiler-private.h>
#include <mono/metadata/profiler.h>
#include <mono/utils/mono-compiler.h>
+#include <mono/metadata/mono-basic-block.h>
#include "mini.h"
#include "trace.h"
#undef MINI_OP
#undef MINI_OP3
-extern GHashTable *jit_icall_name_hash;
-
#define MONO_INIT_VARINFO(vi,id) do { \
(vi)->range.first_use.pos.bid = 0xffff; \
(vi)->reg = -1; \
static int
mono_find_block_region (MonoCompile *cfg, int offset)
{
- MonoMethod *method = cfg->method;
- MonoMethodHeader *header = mono_method_get_header (method);
+ MonoMethodHeader *header = cfg->header;
MonoExceptionClause *clause;
int i;
static GList*
mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
{
- MonoMethod *method = cfg->method;
- MonoMethodHeader *header = mono_method_get_header (method);
+ MonoMethodHeader *header = cfg->header;
MonoExceptionClause *clause;
- MonoBasicBlock *handler;
int i;
GList *res = NULL;
clause = &header->clauses [i];
if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
(!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
- if (clause->flags == type) {
- handler = cfg->cil_offset_to_bb [clause->handler_offset];
- g_assert (handler);
- res = g_list_append (res, handler);
- }
+ if (clause->flags == type)
+ res = g_list_append (res, clause);
}
}
return res;
int pos, vnum;
/* inlining can result in deeper stacks */
- if (slot >= mono_method_get_header (cfg->method)->max_stack)
+ if (slot >= cfg->header->max_stack)
return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
pos = ins->type - 1 + slot * STACK_MAX;
}
}
-/*
- * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
- * stored in "klass_reg" implements the interface "klass".
- */
static void
-mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
+mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
{
int ibitmap_reg = alloc_preg (cfg);
+#ifdef COMPRESSED_INTERFACE_BITMAP
+ MonoInst *args [2];
+ MonoInst *res, *ins;
+ NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
+ MONO_ADD_INS (cfg->cbb, ins);
+ args [0] = ins;
+ if (cfg->compile_aot)
+ EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
+ else
+ EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
+ res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
+#else
int ibitmap_byte_reg = alloc_preg (cfg);
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap));
+ MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
if (cfg->compile_aot) {
int iid_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
}
+#endif
+}
+
+/*
+ * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
+ * stored in "klass_reg" implements the interface "klass".
+ */
+static void
+mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
+{
+ mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
}
/*
static void
mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
{
- int ibitmap_reg = alloc_preg (cfg);
- int ibitmap_byte_reg = alloc_preg (cfg);
-
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap));
-
- if (cfg->compile_aot) {
- int iid_reg = alloc_preg (cfg);
- int shifted_iid_reg = alloc_preg (cfg);
- int ibitmap_byte_address_reg = alloc_preg (cfg);
- int masked_iid_reg = alloc_preg (cfg);
- int iid_one_bit_reg = alloc_preg (cfg);
- int iid_bit_reg = alloc_preg (cfg);
- MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, shifted_iid_reg, iid_reg, 3);
- MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, masked_iid_reg, iid_reg, 7);
- MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
- MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
- MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
- } else {
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
- }
+ mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
}
/*
mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
}
-static void
-mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+static void
+mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
{
int idepth_reg = alloc_preg (cfg);
int stypes_reg = alloc_preg (cfg);
}
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
- if (cfg->compile_aot) {
+ if (klass_ins) {
+ MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
+ } else if (cfg->compile_aot) {
int const_reg = alloc_preg (cfg);
MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
}
-static void
+static void
+mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+{
+ mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
+}
+
+static void
mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
{
int intf_reg = alloc_preg (cfg);
/*
* Variant of the above that takes a register to the class, not the vtable.
*/
-static void
+static void
mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
{
int intf_bit_reg = alloc_preg (cfg);
}
static inline void
-mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
+mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
{
- if (cfg->compile_aot) {
+ if (klass_inst) {
+ MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
+ } else if (cfg->compile_aot) {
int const_reg = alloc_preg (cfg);
MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
}
+static inline void
+mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
+{
+ return mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
+}
+
static inline void
mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
{
}
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
}
+
+static void
+mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
-static void
-mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
+static void
+mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
{
if (klass->rank) {
int rank_reg = alloc_preg (cfg);
int eclass_reg = alloc_preg (cfg);
+ g_assert (!klass_inst);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
}
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
- mini_emit_class_check (cfg, stype, klass);
+ mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
}
}
+static void
+mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
+{
+ return mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
+}
+
static void
mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
{
return ji;
}
-inline static MonoInst*
-mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args);
-
inline static MonoCallInst *
mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
MonoInst **args, int calli, int virtual, int tail)
this_reg = this->dreg;
- MONO_EMIT_NULL_CHECK (cfg, this_reg);
-
#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
+ MONO_EMIT_NULL_CHECK (cfg, this_reg);
+
/* Make a call to delegate->invoke_impl */
call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
call->inst.inst_basereg = this_reg;
call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
vtable_reg = alloc_preg (cfg);
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+ MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
slot_reg = -1;
#ifdef MONO_ARCH_HAVE_IMT
return ins;
}
-static inline MonoInst*
+MonoInst*
mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
{
return mono_emit_method_call_full (cfg, method, mono_method_signature (method), args, this, NULL);
return (MonoInst*)call;
}
-inline static MonoInst*
+MonoInst*
mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
{
MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
}
}
+ /* FIXME: this does the memcpy as well (or
+ should), so we don't need the memcpy
+ afterwards */
mono_emit_jit_icall (cfg, mono_value_copy, iargs);
}
}
int rank_reg = alloc_dreg (cfg ,STACK_I4);
obj_reg = sp [0]->dreg;
- MONO_EMIT_NULL_CHECK (cfg, obj_reg);
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+ MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
/* FIXME: generics */
}
}
+// FIXME: This doesn't work yet (class libs tests fail?)
+#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || mono_class_has_variant_generic_params (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+
/*
* Returns NULL and set the cfg exception on error.
*/
static MonoInst*
-handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
+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);
+ MonoInst *klass_inst = NULL;
+
+ if (context_used) {
+ MonoInst *args [2];
+
+ klass_inst = emit_get_rgctx_klass (cfg, context_used,
+ klass, MONO_RGCTX_INFO_KLASS);
+
+ if (is_complex_isinst (klass)) {
+ /* Complex case, handle by an icall */
+
+ /* obj */
+ args [0] = src;
+
+ /* klass */
+ args [1] = klass_inst;
+
+ return mono_emit_jit_icall (cfg, mono_object_castclass, args);
+ } else {
+ /* Simple case, handled by the code below */
+ }
+ }
NEW_BBLOCK (cfg, is_null_bb);
MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
} else {
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
- mini_emit_castclass (cfg, obj_reg, klass_reg, klass, is_null_bb);
+ mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
}
}
* Returns NULL and set the cfg exception on error.
*/
static MonoInst*
-handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
+handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
{
MonoInst *ins;
MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
int obj_reg = src->dreg;
int vtable_reg = alloc_preg (cfg);
int res_reg = alloc_preg (cfg);
+ MonoInst *klass_inst = NULL;
+
+ if (context_used) {
+ klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+
+ if (is_complex_isinst (klass)) {
+ MonoInst *args [2];
+
+ /* Complex case, handle by an icall */
+
+ /* obj */
+ args [0] = src;
+
+ /* klass */
+ args [1] = klass_inst;
+
+ return mono_emit_jit_icall (cfg, mono_object_isinst, args);
+ } else {
+ /* Simple case, the code below can handle it */
+ }
+ }
NEW_BBLOCK (cfg, is_null_bb);
NEW_BBLOCK (cfg, false_bb);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
+ MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+
if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+ g_assert (!context_used);
/* the is_null_bb target simply copies the input register to the output */
mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
} else {
int klass_reg = alloc_preg (cfg);
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
-
if (klass->rank) {
int rank_reg = alloc_preg (cfg);
int eclass_reg = alloc_preg (cfg);
+ g_assert (!context_used);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
}
} else if (mono_class_is_nullable (klass)) {
+ g_assert (!context_used);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
/* the is_null_bb target simply copies the input register to the output */
mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
} else {
if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
+ g_assert (!context_used);
/* the remoting code is broken, access the class for now */
if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
} else {
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
/* the is_null_bb target simply copies the input register to the output */
- mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, is_null_bb);
+ mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
}
}
}
static gboolean
mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
{
- MonoMethodHeader *header;
+ MonoMethodHeaderSummary header;
MonoVTable *vtable;
#ifdef MONO_ARCH_SOFT_FLOAT
MonoMethodSignature *sig = mono_method_signature (method);
return TRUE;
#endif
- if (method->is_inflated)
- /* Avoid inflating the header */
- header = mono_method_get_header (((MonoMethodInflated*)method)->declaring);
- else
- header = mono_method_get_header (method);
- if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
- (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
- (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
+ if (!mono_method_get_header_summary (method, &header))
+ return FALSE;
+
+ /*runtime, icall and pinvoke are checked by summary call*/
+ if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
- (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
(method->klass->marshalbyref) ||
- !header || header->num_clauses)
+ header.has_clauses)
return FALSE;
/* also consider num_locals? */
inline_limit = INLINE_LENGTH_LIMIT;
inline_limit_inited = TRUE;
}
- if (header->code_size >= inline_limit)
+ if (header.code_size >= inline_limit)
return FALSE;
/*
#if SIZEOF_REGISTER == 8
/* The array reg is 64 bits but the index reg is only 32 */
- index2_reg = alloc_preg (cfg);
- MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
+ if (COMPILE_LLVM (cfg)) {
+ /* Not needed */
+ index2_reg = index_reg;
+ } else {
+ index2_reg = alloc_preg (cfg);
+ MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
+ }
#else
if (index->type == STACK_I8) {
index2_reg = alloc_preg (cfg);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
+ return cfg->cbb->last_ins;
} else
return NULL;
} else if (cmethod->klass == mono_defaults.object_class) {
if (strcmp (cmethod->name, "GetType") == 0) {
int dreg = alloc_preg (cfg);
int vt_reg = alloc_preg (cfg);
- MONO_EMIT_NULL_CHECK (cfg, args [0]->dreg);
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
+ MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
type_from_op (ins, NULL, NULL);
if (strcmp (cmethod->name, "get_Rank") == 0) {
int dreg = alloc_ireg (cfg);
int vtable_reg = alloc_preg (cfg);
- MONO_EMIT_NULL_CHECK (cfg, args [0]->dreg);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, vtable_reg,
- args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg,
+ args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
type_from_op (ins, NULL, NULL);
} else if (strcmp (cmethod->name, "get_Length") == 0) {
int dreg = alloc_ireg (cfg);
- MONO_EMIT_NULL_CHECK (cfg, args [0]->dreg);
- EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
- args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
+ EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg,
+ args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
type_from_op (ins, NULL, NULL);
return ins;
#if HAVE_WRITE_BARRIERS
if (is_ref) {
+ MonoInst *dummy_use;
MonoMethod *write_barrier = mono_gc_get_write_barrier ();
mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
+ EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [1]);
}
#endif
}
}
#if HAVE_WRITE_BARRIERS
if (is_ref) {
+ MonoInst *dummy_use;
MonoMethod *write_barrier = mono_gc_get_write_barrier ();
mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
+ EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [1]);
}
#endif
}
{
if (method->klass == mono_defaults.string_class) {
/* managed string allocation support */
- if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_STRING_ALLOC)) {
+ if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
MonoInst *iargs [2];
MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
MonoMethod *managed_alloc = NULL;
mono_jit_stats.inlineable_methods++;
cmethod->inline_info = 1;
}
+
+ /* allocate local variables */
+ cheader = mono_method_get_header (cmethod);
+
+ if (cheader == NULL || mono_loader_get_last_error ()) {
+ if (cheader)
+ mono_metadata_free_mh (cheader);
+ mono_loader_clear_error ();
+ return 0;
+ }
+
/* allocate space to store the return value */
if (!MONO_TYPE_IS_VOID (fsig->ret)) {
rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
}
- /* allocate local variables */
- cheader = mono_method_get_header (cmethod);
+
prev_locals = cfg->locals;
cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
for (i = 0; i < cheader->num_locals; ++i)
EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
*sp++ = ins;
}
+ mono_metadata_free_mh (cheader);
return costs + 1;
} else {
if (cfg->verbose_level > 2)
/* This gets rid of the newly added bblocks */
cfg->cbb = prev_cbb;
}
+ mono_metadata_free_mh (cheader);
return 0;
}
{
char *method_fname = mono_method_full_name (method, TRUE);
char *method_code;
+ MonoMethodHeader *header = mono_method_get_header (method);
- if (mono_method_get_header (method)->code_size == 0)
+ if (header->code_size == 0)
method_code = g_strdup ("method body is empty.");
else
method_code = mono_disasm_code_one (NULL, method, ip, NULL);
cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
g_free (method_fname);
g_free (method_code);
+ mono_metadata_free_mh (header);
}
static void
return MONO_TYPE_IS_REFERENCE (type);
}
-/**
- * mono_decompose_array_access_opts:
- *
- * Decompose array access opcodes.
- * This should be in decompose.c, but it emits calls so it has to stay here until
- * the old JIT is gone.
- */
-void
-mono_decompose_array_access_opts (MonoCompile *cfg)
-{
- MonoBasicBlock *bb, *first_bb;
-
- /*
- * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
- * can be executed anytime. It should be run before decompose_long
- */
-
- /**
- * Create a dummy bblock and emit code into it so we can use the normal
- * code generation macros.
- */
- cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
- first_bb = cfg->cbb;
-
- for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
- MonoInst *ins;
- MonoInst *prev = NULL;
- MonoInst *dest;
- MonoInst *iargs [3];
- gboolean restart;
-
- if (!bb->has_array_access)
- continue;
-
- if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
-
- cfg->cbb->code = cfg->cbb->last_ins = NULL;
- restart = TRUE;
-
- while (restart) {
- restart = FALSE;
-
- for (ins = bb->code; ins; ins = ins->next) {
- switch (ins->opcode) {
- case OP_LDLEN:
- MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
- NEW_LOAD_MEMBASE (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
- G_STRUCT_OFFSET (MonoArray, max_length));
- MONO_ADD_INS (cfg->cbb, dest);
- break;
- case OP_BOUNDS_CHECK:
- MONO_EMIT_NULL_CHECK (cfg, ins->sreg1); \
- MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
- break;
- case OP_NEWARR:
- if (cfg->opt & MONO_OPT_SHARED) {
- EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
- EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
- MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
- iargs [2]->dreg = ins->sreg1;
-
- dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
- dest->dreg = ins->dreg;
- } else {
- MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
- MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
-
- g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
- NEW_VTABLECONST (cfg, iargs [0], vtable);
- MONO_ADD_INS (cfg->cbb, iargs [0]);
- MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
- iargs [1]->dreg = ins->sreg1;
-
- if (managed_alloc)
- dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
- else
- dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
- dest->dreg = ins->dreg;
- }
- break;
- case OP_STRLEN:
- MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
- NEW_LOAD_MEMBASE (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg,
- ins->sreg1, G_STRUCT_OFFSET (MonoString, length));
- MONO_ADD_INS (cfg->cbb, dest);
- break;
- default:
- break;
- }
-
- g_assert (cfg->cbb == first_bb);
-
- if (cfg->cbb->code || (cfg->cbb != first_bb)) {
- /* Replace the original instruction with the new code sequence */
-
- mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
- first_bb->code = first_bb->last_ins = NULL;
- first_bb->in_count = first_bb->out_count = 0;
- cfg->cbb = first_bb;
- }
- else
- prev = ins;
- }
- }
-
- if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
- }
-}
-
-typedef union {
- guint32 vali [2];
- gint64 vall;
- double vald;
-} DVal;
-
-#ifdef MONO_ARCH_SOFT_FLOAT
-
-/**
- * mono_decompose_soft_float:
- *
- * Soft float support on ARM. We store each double value in a pair of integer vregs,
- * similar to long support on 32 bit platforms. 32 bit float values require special
- * handling when used as locals, arguments, and in calls.
- * One big problem with soft-float is that there are few r4 test cases in our test suite.
- */
-void
-mono_decompose_soft_float (MonoCompile *cfg)
-{
- MonoBasicBlock *bb, *first_bb;
-
- /*
- * This pass creates long opcodes, so it should be run before decompose_long_opts ().
- */
-
- /**
- * Create a dummy bblock and emit code into it so we can use the normal
- * code generation macros.
- */
- cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
- first_bb = cfg->cbb;
-
- for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
- MonoInst *ins;
- MonoInst *prev = NULL;
- gboolean restart;
-
- if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
-
- cfg->cbb->code = cfg->cbb->last_ins = NULL;
- restart = TRUE;
-
- while (restart) {
- restart = FALSE;
-
- for (ins = bb->code; ins; ins = ins->next) {
- const char *spec = INS_INFO (ins->opcode);
-
- /* Most fp operations are handled automatically by opcode emulation */
-
- switch (ins->opcode) {
- case OP_R8CONST: {
- DVal d;
- d.vald = *(double*)ins->inst_p0;
- MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
- break;
- }
- case OP_R4CONST: {
- DVal d;
- /* We load the r8 value */
- d.vald = *(float*)ins->inst_p0;
- MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
- break;
- }
- case OP_FMOVE:
- ins->opcode = OP_LMOVE;
- break;
- case OP_FGETLOW32:
- ins->opcode = OP_MOVE;
- ins->sreg1 = ins->sreg1 + 1;
- break;
- case OP_FGETHIGH32:
- ins->opcode = OP_MOVE;
- ins->sreg1 = ins->sreg1 + 2;
- break;
- case OP_SETFRET: {
- int reg = ins->sreg1;
-
- ins->opcode = OP_SETLRET;
- ins->dreg = -1;
- ins->sreg1 = reg + 1;
- ins->sreg2 = reg + 2;
- break;
- }
- case OP_LOADR8_MEMBASE:
- ins->opcode = OP_LOADI8_MEMBASE;
- break;
- case OP_STORER8_MEMBASE_REG:
- ins->opcode = OP_STOREI8_MEMBASE_REG;
- break;
- case OP_STORER4_MEMBASE_REG: {
- MonoInst *iargs [2];
- int addr_reg;
-
- /* Arg 1 is the double value */
- MONO_INST_NEW (cfg, iargs [0], OP_ARG);
- iargs [0]->dreg = ins->sreg1;
-
- /* Arg 2 is the address to store to */
- addr_reg = mono_alloc_preg (cfg);
- EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
- mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
- restart = TRUE;
- break;
- }
- case OP_LOADR4_MEMBASE: {
- MonoInst *iargs [1];
- MonoInst *conv;
- int addr_reg;
-
- addr_reg = mono_alloc_preg (cfg);
- EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
- conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
- conv->dreg = ins->dreg;
- break;
- }
- case OP_FCALL:
- case OP_FCALL_REG:
- case OP_FCALL_MEMBASE: {
- MonoCallInst *call = (MonoCallInst*)ins;
- if (call->signature->ret->type == MONO_TYPE_R4) {
- MonoCallInst *call2;
- MonoInst *iargs [1];
- MonoInst *conv;
-
- /* Convert the call into a call returning an int */
- MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
- memcpy (call2, call, sizeof (MonoCallInst));
- switch (ins->opcode) {
- case OP_FCALL:
- call2->inst.opcode = OP_CALL;
- break;
- case OP_FCALL_REG:
- call2->inst.opcode = OP_CALL_REG;
- break;
- case OP_FCALL_MEMBASE:
- call2->inst.opcode = OP_CALL_MEMBASE;
- break;
- default:
- g_assert_not_reached ();
- }
- call2->inst.dreg = mono_alloc_ireg (cfg);
- MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
-
- /* FIXME: Optimize this */
-
- /* Emit an r4->r8 conversion */
- EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
- conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
- conv->dreg = ins->dreg;
-
- /* The call sequence might include fp ins */
- restart = TRUE;
- } else {
- switch (ins->opcode) {
- case OP_FCALL:
- ins->opcode = OP_LCALL;
- break;
- case OP_FCALL_REG:
- ins->opcode = OP_LCALL_REG;
- break;
- case OP_FCALL_MEMBASE:
- ins->opcode = OP_LCALL_MEMBASE;
- break;
- default:
- g_assert_not_reached ();
- }
- }
- break;
- }
- case OP_FCOMPARE: {
- MonoJitICallInfo *info;
- MonoInst *iargs [2];
- MonoInst *call, *cmp, *br;
-
- /* Convert fcompare+fbcc to icall+icompare+beq */
-
- info = mono_find_jit_opcode_emulation (ins->next->opcode);
- g_assert (info);
-
- /* Create dummy MonoInst's for the arguments */
- MONO_INST_NEW (cfg, iargs [0], OP_ARG);
- iargs [0]->dreg = ins->sreg1;
- MONO_INST_NEW (cfg, iargs [1], OP_ARG);
- iargs [1]->dreg = ins->sreg2;
-
- call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
-
- MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
- cmp->sreg1 = call->dreg;
- cmp->inst_imm = 0;
- MONO_ADD_INS (cfg->cbb, cmp);
-
- MONO_INST_NEW (cfg, br, OP_IBNE_UN);
- br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
- br->inst_true_bb = ins->next->inst_true_bb;
- br->inst_false_bb = ins->next->inst_false_bb;
- MONO_ADD_INS (cfg->cbb, br);
-
- /* The call sequence might include fp ins */
- restart = TRUE;
-
- /* Skip fbcc or fccc */
- NULLIFY_INS (ins->next);
- break;
- }
- case OP_FCEQ:
- case OP_FCGT:
- case OP_FCGT_UN:
- case OP_FCLT:
- case OP_FCLT_UN: {
- MonoJitICallInfo *info;
- MonoInst *iargs [2];
- MonoInst *call;
-
- /* Convert fccc to icall+icompare+iceq */
-
- info = mono_find_jit_opcode_emulation (ins->opcode);
- g_assert (info);
-
- /* Create dummy MonoInst's for the arguments */
- MONO_INST_NEW (cfg, iargs [0], OP_ARG);
- iargs [0]->dreg = ins->sreg1;
- MONO_INST_NEW (cfg, iargs [1], OP_ARG);
- iargs [1]->dreg = ins->sreg2;
-
- call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
-
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
- MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
-
- /* The call sequence might include fp ins */
- restart = TRUE;
- break;
- }
- case OP_CKFINITE: {
- MonoInst *iargs [2];
- MonoInst *call, *cmp;
-
- /* Convert to icall+icompare+cond_exc+move */
-
- /* Create dummy MonoInst's for the arguments */
- MONO_INST_NEW (cfg, iargs [0], OP_ARG);
- iargs [0]->dreg = ins->sreg1;
-
- call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
-
- MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
- cmp->sreg1 = call->dreg;
- cmp->inst_imm = 1;
- MONO_ADD_INS (cfg->cbb, cmp);
-
- MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
-
- /* Do the assignment if the value is finite */
- MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
-
- restart = TRUE;
- break;
- }
- default:
- if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
- mono_print_ins (ins);
- g_assert_not_reached ();
- }
- break;
- }
-
- g_assert (cfg->cbb == first_bb);
-
- if (cfg->cbb->code || (cfg->cbb != first_bb)) {
- /* Replace the original instruction with the new code sequence */
-
- mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
- first_bb->code = first_bb->last_ins = NULL;
- first_bb->in_count = first_bb->out_count = 0;
- cfg->cbb = first_bb;
- }
- else
- prev = ins;
- }
- }
-
- if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
- }
-
- mono_decompose_long_opts (cfg);
-}
-
-#endif
-
static void
emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
{
MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
guint inline_offset, gboolean is_virtual_call)
{
+ MonoError error;
MonoInst *ins, **sp, **stack_start;
MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
+ MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
MonoMethod *cmethod, *method_definition;
MonoInst **arg_array;
MonoMethodHeader *header;
GSList *class_inits = NULL;
gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
int context_used;
- gboolean init_locals, seq_points;
+ gboolean init_locals, seq_points, skip_dead_blocks;
/* serialization and xdomain stuff may need access to private fields and methods */
dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
}
+ skip_dead_blocks = !dont_verify;
+ if (skip_dead_blocks) {
+ original_bb = bb = mono_basic_block_split (method, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_cleanup (&error);
+ UNVERIFIED;
+ }
+ g_assert (bb);
+ }
+
/* we use a spare stack slot in SWITCH and NEWOBJ and others */
stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
start_new_bblock = 0;
cfg->cbb = bblock;
while (ip < end) {
-
if (cfg->method == method)
cfg->real_offset = ip - header->code;
else
}
}
+ if (skip_dead_blocks) {
+ int ip_offset = ip - header->code;
+
+ if (ip_offset == bb->end)
+ bb = bb->next;
+
+ if (bb->dead) {
+ int op_size = mono_opcode_size (ip, end);
+ g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
+
+ if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
+
+ if (ip_offset + op_size == bb->end) {
+ MONO_INST_NEW (cfg, ins, OP_NOP);
+ MONO_ADD_INS (bblock, ins);
+ start_new_bblock = 1;
+ }
+
+ ip += op_size;
+ continue;
+ }
+ }
/*
* Sequence points are points where the debugger can place a breakpoint.
* Currently, we generate these automatically at points where the IL
array_rank = cmethod->klass->rank;
fsig = mono_method_signature (cmethod);
} else {
- if (mono_method_signature (cmethod)->pinvoke) {
+ fsig = mono_method_signature (cmethod);
+
+ if (!fsig)
+ goto load_error;
+
+ if (fsig->pinvoke) {
MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
check_for_pending_exc, FALSE);
fsig = mono_method_signature (wrapper);
* emit_get_rgctx_method () calls mono_class_vtable () so check
* for type load errors before.
*/
- mono_class_vtable (cfg->domain, cmethod->klass);
+ mono_class_setup_vtable (cmethod->klass);
CHECK_TYPELOAD (cmethod->klass);
}
if (cfg->ret) {
MonoType *ret_type = mono_method_signature (method)->ret;
+ if (seq_points) {
+ /*
+ * Place a seq point here too even through the IL stack is not
+ * empty, so a step over on
+ * call <FOO>
+ * ret
+ * will work correctly.
+ */
+ NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
+
g_assert (!return_var);
CHECK_STACK (1);
--sp;
#if HAVE_WRITE_BARRIERS
if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0))) {
+ MonoInst *dummy_use;
/* insert call to write barrier */
MonoMethod *write_barrier = mono_gc_get_write_barrier ();
mono_emit_method_call (cfg, write_barrier, sp, NULL);
+ EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
}
#endif
if (cfg->generic_sharing_context)
context_used = mono_class_check_context_used (klass);
- if (context_used) {
- MonoInst *args [2];
-
- /* obj */
- args [0] = *sp;
-
- /* klass */
- args [1] = emit_get_rgctx_klass (cfg, context_used,
- klass, MONO_RGCTX_INFO_KLASS);
-
- ins = mono_emit_jit_icall (cfg, mono_object_castclass, args);
- *sp ++ = ins;
- ip += 5;
- inline_costs += 2;
- } else if (mono_class_has_variant_generic_params (klass)) {
+ if (!context_used && mono_class_has_variant_generic_params (klass)) {
MonoInst *args [2];
/* obj */
*sp ++ = ins;
ip += 5;
inline_costs += 2;
- } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
MonoMethod *mono_castclass;
MonoInst *iargs [1];
int costs;
inline_costs += costs;
}
else {
- ins = handle_castclass (cfg, klass, *sp);
+ ins = handle_castclass (cfg, klass, *sp, context_used);
CHECK_CFG_EXCEPTION;
bblock = cfg->cbb;
*sp ++ = ins;
if (cfg->generic_sharing_context)
context_used = mono_class_check_context_used (klass);
- if (context_used) {
- MonoInst *args [2];
-
- /* obj */
- args [0] = *sp;
-
- /* klass */
- args [1] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
-
- *sp = mono_emit_jit_icall (cfg, mono_object_isinst, args);
- sp++;
- ip += 5;
- inline_costs += 2;
- } else if (mono_class_has_variant_generic_params (klass)) {
+ if (!context_used && mono_class_has_variant_generic_params (klass)) {
MonoInst *args [2];
/* obj */
sp++;
ip += 5;
inline_costs += 2;
- } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
MonoMethod *mono_isinst;
MonoInst *iargs [1];
int costs;
inline_costs += costs;
}
else {
- ins = handle_isinst (cfg, klass, *sp);
+ ins = handle_isinst (cfg, klass, *sp, context_used);
CHECK_CFG_EXCEPTION;
bblock = cfg->cbb;
*sp ++ = ins;
*sp++ = iargs [0];
inline_costs += costs;
} else {
- ins = handle_castclass (cfg, klass, *sp);
+ ins = handle_castclass (cfg, klass, *sp, 0);
CHECK_CFG_EXCEPTION;
bblock = cfg->cbb;
*sp ++ = ins;
if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
/* insert call to write barrier */
MonoMethod *write_barrier = mono_gc_get_write_barrier ();
- MonoInst *iargs [2];
+ MonoInst *iargs [2], *dummy_use;
int dreg;
dreg = alloc_preg (cfg);
EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
iargs [1] = sp [1];
mono_emit_method_call (cfg, write_barrier, iargs, NULL);
+
+ EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
}
#endif
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
load->flags |= ins_flag;
+ load->flags |= MONO_INST_FAULT;
*sp++ = load;
}
}
is_special_static = mono_class_field_is_special_static (field);
/* Generate IR to compute the field address */
+ if (is_special_static && ((gsize)addr & 0x80000000) == 0 && mono_get_thread_intrinsic (cfg) && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
+ /*
+ * Fast access to TLS data
+ * Inline version of get_thread_static_data () in
+ * threads.c.
+ */
+ guint32 offset;
+ int idx, static_data_reg, array_reg, dreg;
+ MonoInst *thread_ins;
+
+ // offset &= 0x7fffffff;
+ // idx = (offset >> 24) - 1;
+ // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
+
+ thread_ins = mono_get_thread_intrinsic (cfg);
+ 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, G_STRUCT_OFFSET (MonoInternalThread, static_data));
+
+ if (cfg->compile_aot) {
+ int offset_reg, offset2_reg, idx_reg;
+
+ /* For TLS variables, this will return the TLS offset */
+ EMIT_NEW_SFLDACONST (cfg, ins, field);
+ offset_reg = ins->dreg;
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
+ idx_reg = alloc_ireg (cfg);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
+ MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
+ array_reg = alloc_ireg (cfg);
+ MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
+ offset2_reg = alloc_ireg (cfg);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
+ dreg = alloc_ireg (cfg);
+ EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
+ } else {
+ offset = (gsize)addr & 0x7fffffff;
+ idx = (offset >> 24) - 1;
- if ((cfg->opt & MONO_OPT_SHARED) ||
+ array_reg = alloc_ireg (cfg);
+ MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
+ dreg = alloc_ireg (cfg);
+ EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
+ }
+ } else if ((cfg->opt & MONO_OPT_SHARED) ||
(cfg->compile_aot && is_special_static) ||
(context_used && is_special_static)) {
MonoInst *iargs [2];
else
EMIT_NEW_PCONST (cfg, ins, addr);
} else {
- /*
- * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
- * This could be later optimized to do just a couple of
- * memory dereferences with constant offsets.
- */
MonoInst *iargs [1];
EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
GList *tmp;
+ MonoExceptionClause *clause;
+
for (tmp = handlers; tmp; tmp = tmp->next) {
- tblock = tmp->data;
+ clause = tmp->data;
+ tblock = cfg->cil_offset_to_bb [clause->handler_offset];
+ g_assert (tblock);
link_bblock (cfg, bblock, tblock);
MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
ins->inst_target_bb = tblock;
+ ins->inst_eh_block = clause;
MONO_ADD_INS (bblock, ins);
bblock->has_call_handler = 1;
if (COMPILE_LLVM (cfg)) {
/*
* Optimize the common case of ldftn+delegate creation
*/
-#if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
- /* FIXME: SGEN support */
if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
- MonoInst *target_ins;
MonoMethod *invoke;
int invoke_context_used = 0;
if (cfg->generic_sharing_context)
invoke_context_used = mono_method_check_context_used (invoke);
+#if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
+ /* FIXME: SGEN support */
if (invoke_context_used == 0) {
+ MonoInst *target_ins;
+
ip += 6;
if (cfg->verbose_level > 3)
g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
sp ++;
break;
}
+#endif
}
}
-#endif
argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
CHECK_STACK_OVF (1);
CHECK_OPSIZE (6);
token = read32 (ip + 2);
- if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
+ if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic) {
MonoType *type = mono_type_create_from_typespec (image, token);
token = mono_type_size (type, &ialign);
} else {
}
}
+ if (cfg->init_ref_vars && cfg->method == method) {
+ /* Emit initialization for ref vars */
+ // FIXME: Avoid duplication initialization for IL locals.
+ for (i = 0; i < cfg->num_varinfo; ++i) {
+ MonoInst *ins = cfg->varinfo [i];
+
+ if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
+ MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
+ }
+ }
+
/* Add a sequence point for method entry/exit events */
if (seq_points) {
NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
g_free (mname);
+ mono_metadata_free_mh (header);
+ mono_basic_block_free (original_bb);
return -1;
}
if ((cfg->verbose_level > 2) && (cfg->method == method))
mono_print_code (cfg, "AFTER METHOD-TO-IR");
+ mono_metadata_free_mh (header);
+ mono_basic_block_free (original_bb);
return inline_costs;
exception_exit:
g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
- g_slist_free (class_inits);
- dont_inline = g_list_remove (dont_inline, method);
- return -1;
+ goto cleanup;
inline_failure:
- g_slist_free (class_inits);
- dont_inline = g_list_remove (dont_inline, method);
- return -1;
+ goto cleanup;
load_error:
- g_slist_free (class_inits);
- dont_inline = g_list_remove (dont_inline, method);
cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
- return -1;
+ goto cleanup;
unverified:
+ set_exception_type_from_invalid_il (cfg, method, ip);
+ goto cleanup;
+
+ cleanup:
g_slist_free (class_inits);
+ mono_basic_block_free (original_bb);
dont_inline = g_list_remove (dont_inline, method);
- set_exception_type_from_invalid_il (cfg, method, ip);
+ mono_metadata_free_mh (header);
return -1;
}
* don't split live ranges, these will precisely describe the live range of
* the variable, i.e. the instruction range where a valid value can be found
* in the variables location.
+ * The live range is computed using the liveness info computed by the liveness pass.
+ * We can't use vmv->range, since that is an abstract live range, and we need
+ * one which is instruction precise.
+ * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
*/
/* FIXME: Only do this if debugging info is requested */
live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
if (cfg->verbose_level > 2)
mono_print_ins_index (1, ins);
}
+
+ /* Extend the live range based on the liveness info */
+ if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
+ for (i = 0; i < cfg->num_varinfo; i ++) {
+ MonoMethodVar *vi = MONO_VARINFO (cfg, i);
+
+ if (vreg_is_volatile (cfg, vi->vreg))
+ /* The liveness info is incomplete */
+ continue;
+
+ if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
+ /* Live from at least the first ins of this bb */
+ live_range_start [vi->vreg] = bb->code;
+ live_range_start_bb [vi->vreg] = bb;
+ }
+
+ if (mono_bitset_test_fast (bb->live_out_set, i)) {
+ /* Live at least until the last ins of this bb */
+ live_range_end [vi->vreg] = bb->last_ins;
+ live_range_end_bb [vi->vreg] = bb;
+ }
+ }
+ }
}
#ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
* Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
* by storing the current native offset into MonoMethodVar->live_range_start/end.
*/
- for (i = 0; i < cfg->num_varinfo; ++i) {
- int vreg = MONO_VARINFO (cfg, i)->vreg;
- MonoInst *ins;
-
- if (live_range_start [vreg]) {
- MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
- ins->inst_c0 = i;
- ins->inst_c1 = vreg;
- mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
- }
- if (live_range_end [vreg]) {
- MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
- ins->inst_c0 = i;
- ins->inst_c1 = vreg;
- mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
+ if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
+ for (i = 0; i < cfg->num_varinfo; ++i) {
+ int vreg = MONO_VARINFO (cfg, i)->vreg;
+ MonoInst *ins;
+
+ if (live_range_start [vreg]) {
+ MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
+ ins->inst_c0 = i;
+ ins->inst_c1 = vreg;
+ mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
+ }
+ if (live_range_end [vreg]) {
+ MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
+ ins->inst_c0 = i;
+ ins->inst_c1 = vreg;
+ if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
+ mono_add_ins_to_end (live_range_end_bb [vreg], ins);
+ else
+ mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
+ }
}
}
#endif