#include "jit.h"
#include "debugger-agent.h"
-#define BRANCH_COST 100
+#define BRANCH_COST 10
#define INLINE_LENGTH_LIMIT 20
#define INLINE_FAILURE do {\
if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
extern MonoMethodSignature *helper_sig_class_init_trampoline;
extern MonoMethodSignature *helper_sig_domain_get;
extern MonoMethodSignature *helper_sig_generic_class_init_trampoline;
+extern MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
}
}
-/*
- * 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);
}
/*
}
}
-#endif /* DISABLE_JIT */
-
void
mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
{
}
}
-#ifndef DISABLE_JIT
-
static int
ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
{
static void
emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
{
+ int method_reg;
+
+ if (COMPILE_LLVM (cfg)) {
+ method_reg = alloc_preg (cfg);
+
+ if (imt_arg) {
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
+ } else if (cfg->compile_aot) {
+ MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+ } else {
+ MonoInst *ins;
+ MONO_INST_NEW (cfg, ins, OP_PCONST);
+ ins->inst_p0 = call->method;
+ ins->dreg = method_reg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
+
+#ifdef ENABLE_LLVM
+ call->imt_arg_reg = method_reg;
+#endif
+#ifdef MONO_ARCH_IMT_REG
+ mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
+#else
+ /* Need this to keep the IMT arg alive */
+ mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
+#endif
+ return;
+ }
+
#ifdef MONO_ARCH_IMT_REG
- int method_reg = alloc_preg (cfg);
+ method_reg = alloc_preg (cfg);
if (imt_arg) {
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
return (MonoInst*)call;
}
+static void
+set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
+{
+#ifdef MONO_ARCH_RGCTX_REG
+ mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
+ cfg->uses_rgctx_reg = TRUE;
+ call->rgctx_reg = TRUE;
+#ifdef ENABLE_LLVM
+ call->rgctx_arg_reg = rgctx_reg;
+#endif
+#else
+ NOT_IMPLEMENTED;
+#endif
+}
+
inline static MonoInst*
mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg)
{
-#ifdef MONO_ARCH_RGCTX_REG
MonoCallInst *call;
int rgctx_reg = -1;
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
}
call = (MonoCallInst*)mono_emit_calli (cfg, sig, args, addr);
- if (rgctx_arg) {
- mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
- cfg->uses_rgctx_reg = TRUE;
- call->rgctx_reg = TRUE;
- }
+ if (rgctx_arg)
+ set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
return (MonoInst*)call;
-#else
- g_assert_not_reached ();
- return NULL;
-#endif
}
static MonoInst*
mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *vtable_arg)
{
-#ifdef MONO_ARCH_RGCTX_REG
int rgctx_reg = 0;
-#endif
MonoInst *ins;
MonoCallInst *call;
if (vtable_arg) {
-#ifdef MONO_ARCH_RGCTX_REG
rgctx_reg = mono_alloc_preg (cfg);
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
-#else
- NOT_IMPLEMENTED;
-#endif
}
ins = mono_emit_method_call_full (cfg, method, sig, args, this, imt_arg);
call = (MonoCallInst*)ins;
- if (vtable_arg) {
-#ifdef MONO_ARCH_RGCTX_REG
- mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
- cfg->uses_rgctx_reg = TRUE;
- call->rgctx_reg = TRUE;
-#else
- NOT_IMPLEMENTED;
-#endif
- }
+ if (vtable_arg)
+ set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg);
return ins;
}
return memcpy_method;
}
+static void
+create_write_barrier_bitmap (MonoClass *klass, unsigned *wb_bitmap, int offset)
+{
+ MonoClassField *field;
+ gpointer iter = NULL;
+
+ while ((field = mono_class_get_fields (klass, &iter))) {
+ int foffset;
+
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+ foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
+ if (mono_type_is_reference (field->type)) {
+ g_assert ((foffset % SIZEOF_VOID_P) == 0);
+ *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
+ } else {
+ /*FIXME support nested value types so this works for: struct X { Y y; int z;} struct Y { object a,b; }*/
+ MonoClass *field_class = mono_class_from_mono_type (field->type);
+ if (field_class->has_references)
+ create_write_barrier_bitmap (field_class, wb_bitmap, offset + foffset);
+ }
+ }
+}
+
+static void
+emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_reg)
+{
+#ifdef HAVE_SGEN_GC
+ int card_table_shift_bits;
+ gpointer card_table_mask;
+ guint8 *card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
+ MonoInst *dummy_use;
+
+#ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
+ int nursery_shift_bits;
+ size_t nursery_size;
+
+ mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
+
+ if (!cfg->compile_aot && card_table && nursery_shift_bits > 0) {
+ MonoInst *wbarrier;
+
+ MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
+ wbarrier->sreg1 = ptr->dreg;
+ if (value)
+ wbarrier->sreg2 = value->dreg;
+ else
+ wbarrier->sreg2 = value_reg;
+ MONO_ADD_INS (cfg->cbb, wbarrier);
+ } else
+#endif
+ if (card_table) {
+ int offset_reg = alloc_preg (cfg);
+ int card_reg = alloc_preg (cfg);
+ MonoInst *ins;
+
+ 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);
+
+ /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
+ * IMM's larger than 32bits.
+ */
+ if (cfg->compile_aot) {
+ MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
+ } else {
+ MONO_INST_NEW (cfg, ins, OP_PCONST);
+ ins->inst_p0 = card_table;
+ ins->dreg = card_reg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
+ MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
+ } else {
+ MonoMethod *write_barrier = mono_gc_get_write_barrier ();
+ mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
+ }
+
+ if (value) {
+ EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
+ } else {
+ MONO_INST_NEW (cfg, dummy_use, OP_DUMMY_USE);
+ dummy_use->sreg1 = value_reg;
+ MONO_ADD_INS (cfg->cbb, dummy_use);
+ }
+#endif
+}
+
+static gboolean
+mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
+{
+ int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
+ unsigned need_wb = 0;
+
+ if (align == 0)
+ align = 4;
+
+ /*types with references can't have alignment smaller than sizeof(void*) */
+ if (align < SIZEOF_VOID_P)
+ return FALSE;
+
+ /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
+ if (size > 32 * SIZEOF_VOID_P)
+ return FALSE;
+
+ create_write_barrier_bitmap (klass, &need_wb, 0);
+
+ /* We don't unroll more than 5 stores to avoid code bloat. */
+ if (size > 5 * SIZEOF_VOID_P) {
+ /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
+ size += (SIZEOF_VOID_P - 1);
+ size &= ~(SIZEOF_VOID_P - 1);
+
+ EMIT_NEW_ICONST (cfg, iargs [2], size);
+ EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
+ mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
+ return TRUE;
+ }
+
+ destreg = iargs [0]->dreg;
+ srcreg = iargs [1]->dreg;
+ offset = 0;
+
+ dest_ptr_reg = alloc_preg (cfg);
+ tmp_reg = alloc_preg (cfg);
+
+ /*tmp = dreg*/
+ EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
+
+ while (size >= SIZEOF_VOID_P) {
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, tmp_reg, srcreg, offset);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
+
+ if (need_wb & 0x1)
+ emit_write_barrier (cfg, iargs [0], NULL, tmp_reg);
+
+ offset += SIZEOF_VOID_P;
+ size -= SIZEOF_VOID_P;
+ need_wb >>= 1;
+
+ /*tmp += sizeof (void*)*/
+ if (size >= SIZEOF_VOID_P) {
+ NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
+ MONO_ADD_INS (cfg->cbb, iargs [0]);
+ }
+ }
+
+ /* Those cannot be references since size < sizeof (void*) */
+ while (size >= 4) {
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
+ offset += 4;
+ size -= 4;
+ }
+
+ while (size >= 2) {
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
+ offset += 2;
+ size -= 2;
+ }
+
+ while (size >= 1) {
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
+ offset += 1;
+ size -= 1;
+ }
+
+ return TRUE;
+}
+
/*
* Emit code to copy a valuetype of type @klass whose address is stored in
* @src->dreg to memory whose address is stored at @dest->dreg.
void
mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
{
- MonoInst *iargs [3];
+ MonoInst *iargs [4];
int n;
guint32 align = 0;
MonoMethod *memcpy_method;
else
n = mono_class_value_size (klass, &align);
-#if HAVE_WRITE_BARRIERS
/* if native is true there should be no references in the struct */
- if (klass->has_references && !native) {
+ if (cfg->gen_write_barriers && klass->has_references && !native) {
/* Avoid barriers when storing to the stack */
if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
(dest->opcode == OP_LDADDR))) {
if (cfg->generic_sharing_context)
context_used = mono_class_check_context_used (klass);
- if (context_used) {
+
+ /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
+ if ((cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
+ return;
+ } else if (context_used) {
iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
- } else {
+ } else {
if (cfg->compile_aot) {
EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
} else {
}
}
- /* 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);
+ return;
}
}
-#endif
if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
/* FIXME: Optimize the case when src/dest is OP_LDADDR */
EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
}
- call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
+ if (COMPILE_LLVM (cfg))
+ call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
+ else
+ call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
#ifdef MONO_ARCH_VTABLE_REG
mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
cfg->uses_vtable_reg = TRUE;
if (cfg->generic_sharing_context)
context_used = mono_class_check_context_used (array_class);
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
+ MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
if (cfg->opt & MONO_OPT_SHARED) {
int class_reg = alloc_preg (cfg);
* Returns NULL and set the cfg exception on error.
*/
static MonoInst*
-handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box)
+handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
{
MonoInst *iargs [2];
void *alloc_ftn;
+ if (context_used) {
+ MonoInst *data;
+ int rgctx_info;
+ MonoInst *iargs [2];
+
+ /*
+ FIXME: we cannot get managed_alloc here because we can't get
+ the class's vtable (because it's not a closed class)
+
+ MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+ MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
+ */
+
+ if (cfg->opt & MONO_OPT_SHARED)
+ rgctx_info = MONO_RGCTX_INFO_KLASS;
+ else
+ rgctx_info = MONO_RGCTX_INFO_VTABLE;
+ data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
+
+ if (cfg->opt & MONO_OPT_SHARED) {
+ EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
+ iargs [1] = data;
+ alloc_ftn = mono_object_new;
+ } else {
+ iargs [0] = data;
+ alloc_ftn = mono_object_new_specific;
+ }
+
+ return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
+ }
+
if (cfg->opt & MONO_OPT_SHARED) {
EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
}
-
-static MonoInst*
-handle_alloc_from_inst (MonoCompile *cfg, MonoClass *klass, MonoInst *data_inst,
- gboolean for_box)
-{
- MonoInst *iargs [2];
- MonoMethod *managed_alloc = NULL;
- void *alloc_ftn;
-
- /*
- FIXME: we cannot get managed_alloc here because we can't get
- the class's vtable (because it's not a closed class)
-
- MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
- MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
- */
-
- if (cfg->opt & MONO_OPT_SHARED) {
- EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
- iargs [1] = data_inst;
- alloc_ftn = mono_object_new;
- } else {
- if (managed_alloc) {
- iargs [0] = data_inst;
- return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
- }
-
- iargs [0] = data_inst;
- alloc_ftn = mono_object_new_specific;
- }
-
- return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
-}
/*
* Returns NULL and set the cfg exception on error.
*/
static MonoInst*
-handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass)
+handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
{
MonoInst *alloc, *ins;
if (mono_class_is_nullable (klass)) {
MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
- return mono_emit_method_call (cfg, method, &val, NULL);
+
+ if (context_used) {
+ /* FIXME: What if the class is shared? We might not
+ have to get the method address from the RGCTX. */
+ MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
+ MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
+ MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+
+ return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
+ } else {
+ return mono_emit_method_call (cfg, method, &val, NULL);
+ }
}
- alloc = handle_alloc (cfg, klass, TRUE);
+ alloc = handle_alloc (cfg, klass, TRUE, context_used);
if (!alloc)
return NULL;
return alloc;
}
-static MonoInst *
-handle_box_from_inst (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoInst *data_inst)
-{
- MonoInst *alloc, *ins;
-
- if (mono_class_is_nullable (klass)) {
- MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
- /* FIXME: What if the class is shared? We might not
- have to get the method address from the RGCTX. */
- MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
- MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
- MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
-
- return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
- } else {
- alloc = handle_alloc_from_inst (cfg, klass, data_inst, TRUE);
-
- EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
-
- return alloc;
- }
-}
-
// 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)
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);
+
if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
NEW_BBLOCK (cfg, interface_fail_bb);
MonoDomain *domain;
guint8 **code_slot;
- obj = handle_alloc (cfg, klass, FALSE);
+ obj = handle_alloc (cfg, klass, FALSE, 0);
if (!obj)
return NULL;
}
static MonoInst*
-mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index)
+mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
{
MonoInst *ins;
guint32 size;
}
#endif
- MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
+ if (bcheck)
+ MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
#if defined(TARGET_X86) || defined(TARGET_AMD64)
if (size == 1 || size == 2 || size == 4 || size == 8) {
rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
if (rank == 1)
- return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1]);
+ return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
#ifndef MONO_ARCH_EMULATE_MUL_DIV
/* emit_ldelema_2 depends on OP_LMUL */
}
}
+/* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
+static MonoInst*
+emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
+{
+ MonoInst *addr, *store, *load;
+ MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
+
+ /* the bounds check is already done by the callers */
+ addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
+ if (is_set) {
+ EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
+ EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
+ } else {
+ EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
+ EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
+ }
+ return store;
+}
+
+static MonoInst*
+mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ MonoInst *ins = NULL;
+#ifdef MONO_ARCH_SIMD_INTRINSICS
+ if (cfg->opt & MONO_OPT_SIMD) {
+ ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
+ if (ins)
+ return ins;
+ }
+#endif
+
+ return ins;
+}
+
static MonoInst*
mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
/* Decompose later to allow more optimizations */
EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
ins->type = STACK_I4;
+ ins->flags |= MONO_INST_FAULT;
cfg->cbb->has_array_access = TRUE;
cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
type_from_op (ins, NULL, NULL);
return ins;
-#if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
- } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
+#if !defined(MONO_ARCH_EMULATE_MUL_DIV)
+ } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
int dreg = alloc_ireg (cfg);
int t1 = alloc_ireg (cfg);
} else
return NULL;
} else if (cmethod->klass == mono_defaults.array_class) {
+ if (strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
+ return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
+
+#ifndef MONO_BIG_ARRAYS
+ /*
+ * This is an inline version of GetLength/GetLowerBound(0) used frequently in
+ * Array methods.
+ */
+ if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
+ int dreg = alloc_ireg (cfg);
+ int bounds_reg = alloc_ireg (cfg);
+ MonoBasicBlock *end_bb, *szarray_bb;
+ gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
+
+ NEW_BBLOCK (cfg, end_bb);
+ NEW_BBLOCK (cfg, szarray_bb);
+
+ EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
+ args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
+ /* Non-szarray case */
+ if (get_length)
+ EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
+ bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
+ else
+ EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
+ bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+ MONO_START_BB (cfg, szarray_bb);
+ /* Szarray case */
+ if (get_length)
+ EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
+ args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
+ else
+ MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
+ MONO_START_BB (cfg, end_bb);
+
+ EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
+ ins->type = STACK_I4;
+
+ return ins;
+ }
+#endif
+
if (cmethod->name [0] != 'g')
return NULL;
}
} else if (cmethod->klass == mono_defaults.monitor_class) {
#if defined(MONO_ARCH_MONITOR_OBJECT_REG)
- if (strcmp (cmethod->name, "Enter") == 0) {
+ /* The trampolines don't work under SGEN */
+ gboolean is_moving_gc = mono_gc_is_moving ();
+
+ if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1 && !is_moving_gc) {
MonoCallInst *call;
if (COMPILE_LLVM (cfg)) {
}
return (MonoInst*)call;
- } else if (strcmp (cmethod->name, "Exit") == 0) {
+ } else if (strcmp (cmethod->name, "Exit") == 0 && !is_moving_gc) {
MonoCallInst *call;
if (COMPILE_LLVM (cfg)) {
strcmp (cfg->method->name, "FastMonitorExit") == 0))
return NULL;
- if (strcmp (cmethod->name, "Enter") == 0 ||
+ if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) ||
strcmp (cmethod->name, "Exit") == 0)
fast_method = mono_monitor_get_fast_path (cmethod);
if (!fast_method)
return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
#endif
- } else if (mini_class_is_system_array (cmethod->klass) &&
- strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
- MonoInst *addr, *store, *load;
- MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
-
- addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1]);
- EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
- EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
- return store;
} else if (cmethod->klass->image == mono_defaults.corlib &&
(strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
(strcmp (cmethod->klass->name, "Interlocked") == 0)) {
g_assert_not_reached ();
}
-#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 (cfg->gen_write_barriers && is_ref)
+ emit_write_barrier (cfg, args [0], args [1], -1);
}
#endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
size = 4;
else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
size = sizeof (gpointer);
- else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I4)
+ else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
size = 8;
if (size == 4) {
MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
} else {
/* g_assert_not_reached (); */
}
-#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 (cfg->gen_write_barriers && is_ref)
+ emit_write_barrier (cfg, args [0], args [1], -1);
}
#endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
{
if (method->klass == mono_defaults.string_class) {
/* managed string allocation support */
- if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
+ if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
MonoInst *iargs [2];
MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
MonoMethod *managed_alloc = NULL;
return 0;
}
+ /*Must verify before creating locals as it can cause the JIT to assert.*/
+ if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
+ mono_metadata_free_mh (cheader);
+ 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);
EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
*sp++ = ins;
}
- mono_metadata_free_mh (cheader);
+ cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, 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);
+ cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
return 0;
}
ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
MonoBasicBlock *bblock, unsigned char *ip)
{
- /* there's no restriction to access Transparent or SafeCritical fields, so we only check calls to Critical methods */
- if (mono_security_core_clr_class_level (mono_field_get_parent (field)) != MONO_SECURITY_CORE_CLR_CRITICAL)
- return;
-
/* we can't get the coreclr security level on wrappers since they don't have the attributes */
- caller = get_original_method (caller);
- if (!caller)
- return;
-
- /* caller is Critical! only SafeCritical and Critical callers can access the field, so we throw if caller is Transparent */
- if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
- emit_throw_exception (cfg, mono_get_exception_field_access ());
+ MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
+ if (ex)
+ emit_throw_exception (cfg, ex);
}
static void
ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
MonoBasicBlock *bblock, unsigned char *ip)
{
- /* there's no restriction to call Transparent or SafeCritical code, so we only check calls to Critical methods */
- if (mono_security_core_clr_method_level (callee, TRUE) != MONO_SECURITY_CORE_CLR_CRITICAL)
- return;
-
/* we can't get the coreclr security level on wrappers since they don't have the attributes */
- caller = get_original_method (caller);
- if (!caller)
- return;
-
- /* caller is Critical! only SafeCritical and Critical callers can call it, so we throw if the caller is Transparent */
- if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
- emit_throw_exception (cfg, mono_get_exception_method_access ());
+ MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
+ if (ex)
+ emit_throw_exception (cfg, ex);
}
/*
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);
+ cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
}
static void
image = method->klass->image;
header = mono_method_get_header (method);
+ if (!header) {
+ MonoLoaderError *error;
+
+ if ((error = mono_loader_get_last_error ())) {
+ cfg->exception_type = error->exception_type;
+ } else {
+ cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+ cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
+ }
+ goto exception_exit;
+ }
generic_container = mono_method_get_generic_container (method);
sig = mono_method_signature (method);
num_args = sig->hasthis + sig->param_count;
dont_verify_stloc = TRUE;
}
- if (!dont_verify && mini_method_verify (cfg, method_definition))
- goto exception_exit;
-
if (mono_debug_using_mono_debugger ())
cfg->keep_cil_nops = TRUE;
cfg->bb_exit = end_bblock;
end_bblock->cil_code = NULL;
end_bblock->cil_length = 0;
+ end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
g_assert (cfg->num_bblocks == 2);
arg_array = cfg->args;
/* FIXME: check the signature matches */
cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
- if (!cmethod)
+ if (!cmethod || mono_loader_get_last_error ())
goto load_error;
if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
cil_method = cmethod;
}
- if (!cmethod)
+ if (!cmethod || mono_loader_get_last_error ())
goto load_error;
if (!dont_verify && !cfg->skip_visibility) {
MonoMethod *target_method = cil_method;
/* MS.NET seems to silently convert this to a callvirt */
virtual = 1;
+ {
+ /*
+ * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
+ * converts to a callvirt.
+ *
+ * tests/bug-515884.il is an example of this behavior
+ */
+ const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
+ const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
+ if (!virtual && cmethod->klass->marshalbyref && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
+ virtual = 1;
+ }
+
if (!cmethod->klass->inited)
if (!mono_class_init (cmethod->klass))
goto load_error;
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_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
ins->klass = constrained_call;
- sp [0] = handle_box (cfg, ins, constrained_call);
+ sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call));
CHECK_CFG_EXCEPTION;
} else if (!constrained_call->valuetype) {
int dreg = alloc_preg (cfg);
vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
- if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
- MONO_METHOD_IS_FINAL (cmethod)) {
+ /* !marshalbyref is needed to properly handle generic methods + remoting */
+ if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
+ MONO_METHOD_IS_FINAL (cmethod)) &&
+ !cmethod->klass->marshalbyref) {
if (virtual)
check_this = TRUE;
virtual = 0;
/* Prevent inlining of methods that contain indirect calls */
INLINE_FAILURE;
-#if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK
- /* The llvm vcall trampolines doesn't support generic virtual calls yet */
- if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt && !mono_use_llvm) {
+#if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
+ if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt) {
g_assert (!imt_arg);
if (!context_used)
g_assert (cmethod->is_inflated);
if (!MONO_TYPE_IS_VOID (fsig->ret))
*sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+ CHECK_CFG_EXCEPTION;
+
ip += 5;
ins_flag = 0;
break;
MONO_ADD_INS (bblock, ins);
link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
+
+ CHECK_CFG_EXCEPTION;
+
/* skip CEE_RET as well */
ip += 6;
ins_flag = 0;
/* Conversion to a JIT intrinsic */
if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
+ bblock = cfg->cbb;
if (!MONO_TYPE_IS_VOID (fsig->ret)) {
type_to_eval_stack_type ((cfg), fsig->ret, ins);
*sp = ins;
sp++;
}
+ CHECK_CFG_EXCEPTION;
+
ip += 5;
ins_flag = 0;
break;
INLINE_FAILURE;
if (vtable_arg) {
-#ifdef MONO_ARCH_RGCTX_REG
MonoCallInst *call;
int rgctx_reg = mono_alloc_preg (cfg);
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
call = (MonoCallInst*)ins;
- mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
- cfg->uses_rgctx_reg = TRUE;
- call->rgctx_reg = TRUE;
-#else
- NOT_IMPLEMENTED;
-#endif
+ set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg);
} else {
if (addr->opcode == OP_AOTCONST && addr->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
/*
if (!MONO_TYPE_IS_VOID (fsig->ret))
*sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+ CHECK_CFG_EXCEPTION;
+
ip += 5;
ins_flag = 0;
break;
g_assert_not_reached ();
}
+ CHECK_CFG_EXCEPTION;
+
ip += 5;
ins_flag = 0;
break;
if (!MONO_TYPE_IS_VOID (fsig->ret))
*sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+ CHECK_CFG_EXCEPTION;
+
ip += 5;
ins_flag = 0;
break;
if (!MONO_TYPE_IS_VOID (fsig->ret))
*sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+ CHECK_CFG_EXCEPTION;
+
ip += 5;
ins_flag = 0;
break;
target = ip + n * sizeof (guint32);
GET_BBLOCK (cfg, default_bblock, target);
+ default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
for (i = 0; i < n; ++i) {
GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
targets [i] = tblock;
+ targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
ip += 4;
}
ins_flag = 0;
MONO_ADD_INS (bblock, ins);
-#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->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
+ emit_write_barrier (cfg, sp [0], sp [1], -1);
inline_costs += 1;
++ip;
case CEE_CONV_U:
CHECK_STACK (1);
ADD_UNOP (*ip);
+ CHECK_CFG_EXCEPTION;
ip++;
break;
case CEE_ADD_OVF:
NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
store->flags |= ins_flag;
MONO_ADD_INS (cfg->cbb, store);
+
+ if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
+ emit_write_barrier (cfg, sp [0], sp [1], -1);
} else {
mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
}
CHECK_OPSIZE (5);
token = read32 (ip + 1);
cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
- if (!cmethod)
+ if (!cmethod || mono_loader_get_last_error ())
goto load_error;
fsig = mono_method_get_signature (cmethod, image, token);
if (!fsig)
ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
}
+ if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable_impl (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
+ emit_generic_class_init (cfg, cmethod->klass);
+ CHECK_TYPELOAD (cmethod->klass);
+ }
+
if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
* will be transformed into a normal call there.
*/
} else if (context_used) {
- MonoInst *data;
- int rgctx_info;
-
- if (cfg->opt & MONO_OPT_SHARED)
- rgctx_info = MONO_RGCTX_INFO_KLASS;
- else
- rgctx_info = MONO_RGCTX_INFO_VTABLE;
- data = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, rgctx_info);
-
- alloc = handle_alloc_from_inst (cfg, cmethod->klass, data, FALSE);
+ alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
*sp = alloc;
} else {
MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
class_inits = g_slist_prepend (class_inits, vtable);
}
- alloc = handle_alloc (cfg, cmethod->klass, FALSE);
+ alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
*sp = alloc;
}
CHECK_CFG_EXCEPTION; /*for handle_alloc*/
if (cmethod->klass->marshalbyref)
callvirt_this_arg = sp [0];
+
+ if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
+ if (!MONO_TYPE_IS_VOID (fsig->ret)) {
+ type_to_eval_stack_type ((cfg), fsig->ret, ins);
+ *sp = ins;
+ sp++;
+ }
+
+ CHECK_CFG_EXCEPTION;
+ } else
+
+
+
if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
mono_method_check_inlining (cfg, cmethod) &&
!mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
if (generic_class_is_reference_type (cfg, klass)) {
/* CASTCLASS FIXME kill this huge slice of duplicated code*/
- if (context_used) {
- MonoInst *iargs [2];
-
- /* obj */
- iargs [0] = *sp;
- /* klass */
- iargs [1] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
- ins = mono_emit_jit_icall (cfg, mono_object_castclass, iargs);
- *sp ++ = ins;
- ip += 5;
- inline_costs += 2;
- } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
MonoMethod *mono_castclass;
MonoInst *iargs [1];
int costs;
*sp++ = iargs [0];
inline_costs += costs;
} else {
- ins = handle_castclass (cfg, klass, *sp, 0);
+ ins = handle_castclass (cfg, klass, *sp, context_used);
CHECK_CFG_EXCEPTION;
bblock = cfg->cbb;
*sp ++ = ins;
if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
UNVERIFIED;
/* frequent check in generic code: box (struct), brtrue */
+
+ // FIXME: LLVM can't handle the inconsistent bb linking
if (!mono_class_is_nullable (klass) &&
- ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
- /*printf ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
+ ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
+ (ip [5] == CEE_BRTRUE ||
+ ip [5] == CEE_BRTRUE_S ||
+ ip [5] == CEE_BRFALSE ||
+ ip [5] == CEE_BRFALSE_S)) {
+ gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
+ int dreg;
+ MonoBasicBlock *true_bb, *false_bb;
+
ip += 5;
- MONO_INST_NEW (cfg, ins, OP_BR);
- if (*ip == CEE_BRTRUE_S) {
+
+ if (cfg->verbose_level > 3) {
+ printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
+ printf ("<box+brtrue opt>\n");
+ }
+
+ switch (*ip) {
+ case CEE_BRTRUE_S:
+ case CEE_BRFALSE_S:
CHECK_OPSIZE (2);
ip++;
target = ip + 1 + (signed char)(*ip);
ip++;
- } else {
+ break;
+ case CEE_BRTRUE:
+ case CEE_BRFALSE:
CHECK_OPSIZE (5);
ip++;
target = ip + 4 + (gint)(read32 (ip));
ip += 4;
+ break;
+ default:
+ g_assert_not_reached ();
}
- GET_BBLOCK (cfg, tblock, target);
- link_bblock (cfg, bblock, tblock);
- ins->inst_target_bb = tblock;
- GET_BBLOCK (cfg, tblock, ip);
+
/*
- * This leads to some inconsistency, since the two bblocks are
- * not really connected, but it is needed for handling stack
+ * We need to link both bblocks, since it is needed for handling stack
* arguments correctly (See test_0_box_brtrue_opt_regress_81102).
- * FIXME: This should only be needed if sp != stack_start, but that
- * doesn't work for some reason (test failure in mcs/tests on x86).
+ * Branching to only one of them would lead to inconsistencies, so
+ * generate an ICONST+BRTRUE, the branch opts will get rid of them.
*/
- link_bblock (cfg, bblock, tblock);
+ GET_BBLOCK (cfg, true_bb, target);
+ GET_BBLOCK (cfg, false_bb, ip);
+
+ mono_link_bblock (cfg, cfg->cbb, true_bb);
+ mono_link_bblock (cfg, cfg->cbb, false_bb);
+
if (sp != stack_start) {
handle_stack_args (cfg, stack_start, sp - stack_start);
sp = stack_start;
CHECK_UNVERIFIABLE (cfg);
}
- MONO_ADD_INS (bblock, ins);
+
+ if (COMPILE_LLVM (cfg)) {
+ dreg = alloc_ireg (cfg);
+ MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
+
+ MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
+ } else {
+ /* The JIT can't eliminate the iconst+compare */
+ MONO_INST_NEW (cfg, ins, OP_BR);
+ ins->inst_target_bb = is_true ? true_bb : false_bb;
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
+
start_new_bblock = 1;
break;
}
- if (context_used) {
- MonoInst *data;
- int rgctx_info;
-
- if (cfg->opt & MONO_OPT_SHARED)
- rgctx_info = MONO_RGCTX_INFO_KLASS;
- else
- rgctx_info = MONO_RGCTX_INFO_VTABLE;
- data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
- *sp++ = handle_box_from_inst (cfg, val, klass, context_used, data);
- } else {
- *sp++ = handle_box (cfg, val, klass);
- }
+ *sp++ = handle_box (cfg, val, klass, context_used);
CHECK_CFG_EXCEPTION;
ip += 5;
MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
+ if (sp [0]->opcode != OP_LDADDR)
+ store->flags |= MONO_INST_FAULT;
-#if HAVE_WRITE_BARRIERS
- if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
+ if (cfg->gen_write_barriers && 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], *dummy_use;
+ MonoInst *ptr;
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]);
+ EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
+ emit_write_barrier (cfg, ptr, sp [1], -1);
}
-#endif
store->flags |= ins_flag;
}
sp [0] = ins;
}
- MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
-
if (*ip == CEE_LDFLDA) {
+ if (sp [0]->type == STACK_OBJ) {
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
+ MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
+ }
+
dreg = alloc_preg (cfg);
EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
} else {
MonoInst *load;
+ MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
+
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
load->flags |= ins_flag;
- load->flags |= MONO_INST_FAULT;
+ if (sp [0]->opcode != OP_LDADDR)
+ load->flags |= MONO_INST_FAULT;
*sp++ = load;
}
}
depth, field->offset);
*/
- if (mono_class_needs_cctor_run (klass, method)) {
- MonoCallInst *call;
- MonoInst *vtable;
-
- vtable = emit_get_rgctx_klass (cfg, context_used,
- klass, MONO_RGCTX_INFO_VTABLE);
-
- // FIXME: This doesn't work since it tries to pass the argument
- // in the normal way, instead of using MONO_ARCH_VTABLE_REG
- /*
- * The vtable pointer is always passed in a register regardless of
- * the calling convention, so assign it manually, and make a call
- * using a signature without parameters.
- */
- call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable);
-#ifdef MONO_ARCH_VTABLE_REG
- mono_call_inst_add_outarg_reg (cfg, call, vtable->dreg, MONO_ARCH_VTABLE_REG, FALSE);
- cfg->uses_vtable_reg = TRUE;
-#else
- NOT_IMPLEMENTED;
-#endif
- }
+ if (mono_class_needs_cctor_run (klass, method))
+ emit_generic_class_init (cfg, klass);
/*
* The pointer we're computing here is
EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
sp++;
break;
-#ifndef HAVE_MOVING_COLLECTOR
case MONO_TYPE_I:
case MONO_TYPE_U:
- case MONO_TYPE_STRING:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_SZARRAY:
case MONO_TYPE_PTR:
case MONO_TYPE_FNPTR:
- case MONO_TYPE_ARRAY:
EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
type_to_eval_stack_type ((cfg), field->type, *sp);
sp++;
break;
-#endif
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_ARRAY:
+ if (!mono_gc_is_moving ()) {
+ EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
+ type_to_eval_stack_type ((cfg), field->type, *sp);
+ sp++;
+ } else {
+ is_const = FALSE;
+ }
+ break;
case MONO_TYPE_I8:
case MONO_TYPE_U8:
EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
CHECK_TYPELOAD (klass);
/* FIXME: should check item at sp [1] is compatible with the type of the store. */
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
+ if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
+ generic_class_is_reference_type (cfg, klass)) {
+ /* insert call to write barrier */
+ emit_write_barrier (cfg, sp [0], sp [1], -1);
+ }
ins_flag = 0;
ip += 5;
inline_costs += 1;
allocator because we can't get the
open generic class's vtable. We
have the same problem in
- handle_alloc_from_inst(). This
+ handle_alloc(). This
needs to be solved so that we can
have managed allocs of shared
generic classes. */
ins->dreg = alloc_preg (cfg);
ins->sreg1 = sp [0]->dreg;
ins->type = STACK_I4;
+ /* This flag will be inherited by the decomposition */
+ ins->flags |= MONO_INST_FAULT;
MONO_ADD_INS (cfg->cbb, ins);
cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
cfg->cbb->has_array_access = TRUE;
}
readonly = FALSE;
- ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
+ ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
*sp++ = ins;
ip += 5;
break;
MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
} else {
- addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
+ addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
}
*sp++ = ins;
MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
} else {
- addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
+ addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
}
}
CHECK_OPSIZE (6);
n = read32 (ip + 2);
cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
- if (!cmethod)
+ if (!cmethod || mono_loader_get_last_error ())
goto load_error;
mono_class_init (cmethod->klass);
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)
+#if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
/* FIXME: SGEN support */
- if (invoke_context_used == 0) {
+ if (!cfg->gen_write_barriers && invoke_context_used == 0) {
MonoInst *target_ins;
ip += 6;
CHECK_OPSIZE (6);
n = read32 (ip + 2);
cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
- if (!cmethod)
+ if (!cmethod || mono_loader_get_last_error ())
goto load_error;
mono_class_init (cmethod->klass);
MONO_INST_NEW (cfg, ins, OP_RETHROW);
ins->sreg1 = load->dreg;
MONO_ADD_INS (bblock, ins);
+
+ MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
+ MONO_ADD_INS (bblock, ins);
+
sp = stack_start;
link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
MONO_ADD_INS (cfg->cbb, store);
}
-#ifdef TARGET_POWERPC
+#if defined(TARGET_POWERPC) || defined(TARGET_X86)
if (cfg->compile_aot)
/* FIXME: The plt slots require a GOT var even if the method doesn't use it */
mono_get_got_var (cfg);
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);
+ cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, 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);
+ cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
mono_basic_block_free (original_bb);
return inline_costs;
g_slist_free (class_inits);
mono_basic_block_free (original_bb);
dont_inline = g_list_remove (dont_inline, method);
- mono_metadata_free_mh (header);
+ cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
return -1;
}
#endif
#ifdef TARGET_AMD64
- switch (opcode) {
- case OP_ICOMPARE:
- if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
+ if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
+ switch (opcode) {
+ case OP_ICOMPARE:
return OP_AMD64_ICOMPARE_REG_MEMBASE;
- break;
- case OP_COMPARE:
- case OP_LCOMPARE:
- if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
- return OP_AMD64_COMPARE_REG_MEMBASE;
- break;
- case OP_IADD:
- if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
+ case OP_IADD:
return OP_X86_ADD_REG_MEMBASE;
- case OP_ISUB:
- if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
+ case OP_ISUB:
return OP_X86_SUB_REG_MEMBASE;
- case OP_IAND:
- if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
+ case OP_IAND:
return OP_X86_AND_REG_MEMBASE;
- case OP_IOR:
- if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
+ case OP_IOR:
return OP_X86_OR_REG_MEMBASE;
- case OP_IXOR:
- if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
+ case OP_IXOR:
return OP_X86_XOR_REG_MEMBASE;
- case OP_LADD:
- if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
+ }
+ } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
+ switch (opcode) {
+ case OP_COMPARE:
+ case OP_LCOMPARE:
+ return OP_AMD64_COMPARE_REG_MEMBASE;
+ case OP_LADD:
return OP_AMD64_ADD_REG_MEMBASE;
- case OP_LSUB:
- if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
+ case OP_LSUB:
return OP_AMD64_SUB_REG_MEMBASE;
- case OP_LAND:
- if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
+ case OP_LAND:
return OP_AMD64_AND_REG_MEMBASE;
- case OP_LOR:
- if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
+ case OP_LOR:
return OP_AMD64_OR_REG_MEMBASE;
- case OP_LXOR:
- if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
+ case OP_LXOR:
return OP_AMD64_XOR_REG_MEMBASE;
+ }
}
#endif
case OP_LSHR:
case OP_LSHL:
case OP_LSHR_UN:
+ return -1;
#endif
#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
case OP_IDIV:
case OP_IDIV_UN:
case OP_IREM:
case OP_IREM_UN:
-#endif
return -1;
+#endif
default:
return mono_op_to_op_imm (opcode);
}