#include <mono/metadata/rawbuffer.h>
#include <mono/metadata/security-core-clr.h>
#include <mono/metadata/verify.h>
+#include <mono/metadata/verify-internals.h>
#include <mono/utils/mono-math.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-logger.h>
#include <mono/utils/mono-mmap.h>
+#include <mono/utils/dtrace.h>
#include "mini.h"
#include <string.h>
} while (0)
#define GENERIC_SHARING_FAILURE(opcode) do { \
if (cfg->generic_sharing_context) { \
- /*g_print ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__)*/; \
+ if (cfg->verbose_level > 1) \
+ printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; \
goto exception_exit; \
} \
if (method->klass->valuetype) \
GENERIC_SHARING_FAILURE ((opcode)); \
} while (0)
+#define GET_RGCTX(rgctx) do { \
+ MonoInst *this = NULL; \
+ GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip); \
+ if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) \
+ NEW_ARGLOAD (cfg, this, 0); \
+ (rgctx) = get_runtime_generic_context (cfg, method, this, ip); \
+ } while (0)
#define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
static gboolean default_opt_set = FALSE;
guint32 mono_jit_tls_id = -1;
+
+#ifdef HAVE_KW_THREAD
+static __thread gpointer mono_jit_tls MONO_TLS_FAST;
+#endif
+
MonoTraceSpec *mono_jit_trace_calls = NULL;
gboolean mono_break_on_exc = FALSE;
#ifndef DISABLE_AOT
/* Whenever to check for pending exceptions in managed-to-native wrappers */
gboolean check_for_pending_exc = TRUE;
-/* Whenever to run the verifier on all methods */
-gboolean mono_verify_all = FALSE;
-
gboolean
mono_running_on_valgrind (void)
{
} while (0)
#define NEW_PCONST(cfg,dest,val) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = OP_PCONST; \
+ MONO_INST_NEW ((cfg), (dest), OP_PCONST); \
(dest)->inst_p0 = (val); \
(dest)->type = STACK_PTR; \
} while (0)
#ifdef MONO_ARCH_NEED_GOT_VAR
#define NEW_PATCH_INFO(cfg,dest,el1,el2) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = OP_PATCH_INFO; \
+ MONO_INST_NEW ((cfg), (dest), OP_PATCH_INFO); \
(dest)->inst_left = (gpointer)(el1); \
(dest)->inst_right = (gpointer)(el2); \
} while (0)
#define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
if (cfg->compile_aot) { \
MonoInst *group, *got_var, *got_loc; \
#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
MonoInst *group, *got_var, *got_loc; \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = OP_GOT_ENTRY; \
+ MONO_INST_NEW ((cfg), (dest), OP_GOT_ENTRY); \
got_loc = mono_get_got_var (cfg); \
NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
NEW_PATCH_INFO ((cfg), group, NULL, patch_type); \
#else
#define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST; \
(dest)->inst_p0 = (cons); \
(dest)->inst_i1 = (gpointer)(patch_type); \
} while (0)
#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = OP_AOTCONST; \
+ MONO_INST_NEW ((cfg), (dest), OP_AOTCONST); \
(dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
(dest)->inst_p1 = (gpointer)(patch_type); \
(dest)->type = (stack_type); \
#define NEW_ARGLOAD(cfg,dest,num) do { \
if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->ssa_op = MONO_SSA_LOAD; \
(dest)->inst_i0 = arg_array [(num)]; \
(dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
}} while (0)
#define NEW_LOCLOAD(cfg,dest,num) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->ssa_op = MONO_SSA_LOAD; \
(dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
(dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
} while (0)
#define NEW_LOCLOADA(cfg,dest,num) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
(dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
(dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
(dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
- (dest)->opcode = OP_LDADDR; \
(dest)->type = STACK_MP; \
(dest)->klass = (dest)->inst_i0->klass; \
if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
#define NEW_RETLOADA(cfg,dest) do { \
if (cfg->vret_addr) { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->ssa_op = MONO_SSA_LOAD; \
(dest)->inst_i0 = cfg->vret_addr; \
(dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
(dest)->type = STACK_MP; \
(dest)->klass = (dest)->inst_i0->klass; \
} else { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
(dest)->inst_i0 = (cfg)->ret; \
(dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
#define NEW_ARGLOADA(cfg,dest,num) do { \
if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
(dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
(dest)->inst_i0 = arg_array [(num)]; \
(dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
- (dest)->opcode = OP_LDADDR; \
(dest)->type = STACK_MP; \
(dest)->klass = (dest)->inst_i0->klass; \
(cfg)->disable_ssa = TRUE; \
} while (0)
#define NEW_TEMPLOAD(cfg,dest,num) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->ssa_op = MONO_SSA_LOAD; \
(dest)->inst_i0 = (cfg)->varinfo [(num)]; \
(dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
} while (0)
#define NEW_TEMPLOADA(cfg,dest,num) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
(dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
(dest)->inst_i0 = (cfg)->varinfo [(num)]; \
(dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
- (dest)->opcode = OP_LDADDR; \
(dest)->type = STACK_MP; \
(dest)->klass = (dest)->inst_i0->klass; \
if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
#define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->inst_left = addr; \
(dest)->opcode = mini_type_to_ldind ((cfg), vtype); \
type_to_eval_stack_type ((cfg), vtype, (dest)); \
} while (0)
#define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->inst_i0 = addr; \
(dest)->opcode = mini_type_to_stind ((cfg), vtype); \
(dest)->inst_i1 = (value); \
} while (0)
#define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->ssa_op = MONO_SSA_STORE; \
(dest)->inst_i0 = (cfg)->varinfo [(num)]; \
(dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
} while (0)
#define NEW_LOCSTORE(cfg,dest,num,inst) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
(dest)->ssa_op = MONO_SSA_STORE; \
(dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
#define NEW_ARGSTORE(cfg,dest,num,inst) do { \
if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_NOP); \
(dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
(dest)->ssa_op = MONO_SSA_STORE; \
(dest)->inst_i0 = arg_array [(num)]; \
MONO_INST_NEW (cfg, dest, OP_MEMCPY); \
(dest)->inst_left = (dst); \
(dest)->inst_right = (src); \
- (dest)->cil_code = ip; \
(dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
(dest)->backend.memcpy_args->size = (memcpy_size); \
(dest)->backend.memcpy_args->align = (memcpy_align); \
MONO_INST_NEW (cfg, dest, OP_MEMSET); \
(dest)->inst_left = (dst); \
(dest)->inst_imm = (imm); \
- (dest)->cil_code = ip; \
(dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
(dest)->backend.memcpy_args->size = (memcpy_size); \
(dest)->backend.memcpy_args->align = (memcpy_align); \
} while (0)
#define NEW_DUMMY_USE(cfg,dest,load) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = OP_DUMMY_USE; \
+ MONO_INST_NEW ((cfg), (dest), OP_DUMMY_USE); \
(dest)->inst_left = (load); \
} while (0)
#define NEW_DUMMY_STORE(cfg,dest,num) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ MONO_INST_NEW ((cfg), (dest), OP_DUMMY_STORE); \
(dest)->inst_i0 = (cfg)->varinfo [(num)]; \
- (dest)->opcode = OP_DUMMY_STORE; \
(dest)->klass = (dest)->inst_i0->klass; \
} while (0)
#define ADD_BINOP(op) do { \
MONO_INST_NEW (cfg, ins, (op)); \
- ins->cil_code = ip; \
sp -= 2; \
ins->inst_i0 = sp [0]; \
ins->inst_i1 = sp [1]; \
#define ADD_UNOP(op) do { \
MONO_INST_NEW (cfg, ins, (op)); \
- ins->cil_code = ip; \
sp--; \
ins->inst_i0 = sp [0]; \
*sp++ = ins; \
} while (0)
#define NEW_LDELEMA(cfg,dest,sp,k) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = CEE_LDELEMA; \
+ MONO_INST_NEW ((cfg), (dest), CEE_LDELEMA); \
(dest)->inst_left = (sp) [0]; \
(dest)->inst_right = (sp) [1]; \
(dest)->type = STACK_MP; \
} while (0)
#define NEW_GROUP(cfg,dest,el1,el2) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = OP_GROUP; \
+ MONO_INST_NEW ((cfg), (dest), OP_GROUP); \
(dest)->inst_left = (el1); \
(dest)->inst_right = (el2); \
} while (0)
}
static MonoInst *
-mono_get_rgctx_var (MonoCompile *cfg)
+mono_get_vtable_var (MonoCompile *cfg)
{
g_assert (cfg->generic_sharing_context);
* bb->in_stack, if the basic block is before or after the joint point).
* If the stack merge fails at a join point, cfg->unverifiable is set.
*/
-static int
-handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
+static void
+handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count)
+{
int i, bindex;
MonoBasicBlock *outb;
MonoInst *inst, **locals;
gboolean found;
if (!count)
- return 0;
+ return;
if (cfg->verbose_level > 3)
g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
if (outb->flags & BB_EXCEPTION_HANDLER)
continue;
if (outb->in_scount) {
- if (outb->in_scount != bb->out_scount)
- G_BREAKPOINT ();
+ if (outb->in_scount != bb->out_scount) {
+ cfg->unverifiable = TRUE;
+ return;
+ }
continue; /* check they are the same locals */
}
outb->in_scount = count;
bindex ++;
}
}
-
- return 0;
}
static int
static MonoCallInst*
mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
- MonoInst **args, MonoInst *rgctx_arg, const guint8 *ip, MonoInst *this)
+ MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg, const guint8 *ip, MonoInst *this)
{
MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
+ g_assert (!(rgctx_arg && imt_arg));
+
if (rgctx_arg) {
switch (call->inst.opcode) {
case OP_CALL: call->inst.opcode = OP_CALL_RGCTX; break;
g_assert (!call->inst.inst_right);
call->inst.inst_right = rgctx_arg;
}
+ } else if (imt_arg) {
+ switch (call->inst.opcode) {
+ case OP_CALLVIRT: call->inst.opcode = OP_CALLVIRT_IMT; break;
+ case OP_VOIDCALLVIRT: call->inst.opcode = OP_VOIDCALLVIRT_IMT; break;
+ case OP_FCALLVIRT: call->inst.opcode = OP_FCALLVIRT_IMT; break;
+ case OP_LCALLVIRT: call->inst.opcode = OP_LCALLVIRT_IMT; break;
+ case OP_VCALLVIRT: {
+ MonoInst *group;
+
+ NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
+ call->inst.inst_left = group;
+ call->inst.opcode = OP_VCALLVIRT_IMT;
+ break;
+ }
+ default: g_assert_not_reached ();
+ }
+
+ if (call->inst.opcode != OP_VCALLVIRT_IMT) {
+ g_assert (!call->inst.inst_right);
+ call->inst.inst_right = imt_arg;
+ } else {
+ g_assert (!call->inst.inst_left->inst_right);
+ call->inst.inst_left->inst_right = imt_arg;
+ }
}
return call;
inline static int
mono_emit_rgctx_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
- MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, const guint8 *ip,
- MonoInst *this)
+ MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg,
+ const guint8 *ip, MonoInst *this)
{
- MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, ip, this);
+ MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, imt_arg, ip, this);
return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
}
}
static int
-handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *vtable_inst,
+handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *data_inst,
gboolean for_box, const guchar *ip)
{
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)
MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
*/
- g_assert (!(cfg->opt & MONO_OPT_SHARED));
- g_assert (!cfg->compile_aot);
-
- if (managed_alloc) {
- iargs [0] = vtable_inst;
- return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
- }
+ if (cfg->opt & MONO_OPT_SHARED) {
+ NEW_DOMAINCONST (cfg, iargs [0]);
+ iargs [1] = data_inst;
+ alloc_ftn = mono_object_new;
+ } else {
+ g_assert (!cfg->compile_aot);
- iargs [0] = vtable_inst;
+ if (managed_alloc) {
+ iargs [0] = data_inst;
+ return mono_emit_method_call_spilled (cfg, bblock, managed_alloc,
+ mono_method_signature (managed_alloc), iargs, ip, NULL);
+ }
- return mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
-}
+ iargs [0] = data_inst;
+ alloc_ftn = mono_object_new_specific;
+ }
-/**
- * Handles unbox of a Nullable<T>, returning a temp variable
- * where the result is stored
- */
-static int
-handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
-{
- MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
- return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
-
+ return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
}
-
static MonoInst*
handle_box_copy (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass, int temp)
{
static MonoInst *
handle_box_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip,
- MonoClass *klass, MonoInst *vtable_inst)
+ MonoClass *klass, MonoInst *data_inst)
{
int temp;
g_assert (!mono_class_is_nullable (klass));
- temp = handle_alloc_from_inst (cfg, bblock, klass, vtable_inst, TRUE, ip);
+ temp = handle_alloc_from_inst (cfg, bblock, klass, data_inst, TRUE, ip);
return handle_box_copy (cfg, bblock, val, ip, klass, temp);
}
NEW_TEMPLOAD (cfg, obj, temp);
NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, target));
MONO_INST_NEW (cfg, ins, OP_PADD);
- ins->cil_code = ip;
ins->inst_left = obj;
ins->inst_right = offset_ins;
MONO_INST_NEW (cfg, store, CEE_STIND_REF);
- store->cil_code = ip;
store->inst_left = ins;
store->inst_right = target;
mono_bblock_add_inst (bblock, store);
NEW_TEMPLOAD (cfg, obj, temp);
NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, method));
MONO_INST_NEW (cfg, ins, OP_PADD);
- ins->cil_code = ip;
ins->inst_left = obj;
ins->inst_right = offset_ins;
NEW_METHODCONST (cfg, method_ins, method);
MONO_INST_NEW (cfg, store, CEE_STIND_I);
- store->cil_code = ip;
store->inst_left = ins;
store->inst_right = method_ins;
mono_bblock_add_inst (bblock, store);
NEW_TEMPLOAD (cfg, obj, temp);
NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, invoke_impl));
MONO_INST_NEW (cfg, ins, OP_PADD);
- ins->cil_code = ip;
ins->inst_left = obj;
ins->inst_right = offset_ins;
NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
MONO_INST_NEW (cfg, store, CEE_STIND_I);
- store->cil_code = ip;
store->inst_left = ins;
store->inst_right = tramp_ins;
mono_bblock_add_inst (bblock, store);
#endif
}
+ /* also consider num_locals? */
+ /* Do the size check early to avoid creating vtables */
+ if (getenv ("MONO_INLINELIMIT")) {
+ if (header->code_size >= atoi (getenv ("MONO_INLINELIMIT"))) {
+ return FALSE;
+ }
+ } else if (header->code_size >= INLINE_LENGTH_LIMIT)
+ return FALSE;
+
/*
* if we can initialize the class of the method right away, we do,
* otherwise we don't allow inlining if the class needs initialization,
* inside the inlined code
*/
if (!(cfg->opt & MONO_OPT_SHARED)) {
- vtable = mono_class_vtable (cfg->domain, method->klass);
if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
if (cfg->run_cctors && method->klass->has_cctor) {
+ if (!method->klass->runtime_info)
+ /* No vtable created yet */
+ return FALSE;
+ vtable = mono_class_vtable (cfg->domain, method->klass);
+ if (!vtable)
+ return FALSE;
/* This makes so that inline cannot trigger */
/* .cctors: too many apps depend on them */
/* running with a specific order... */
return FALSE;
mono_runtime_class_init (vtable);
}
+ } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
+ if (!method->klass->runtime_info)
+ /* No vtable created yet */
+ return FALSE;
+ vtable = mono_class_vtable (cfg->domain, method->klass);
+ if (!vtable)
+ return FALSE;
+ if (!vtable->initialized)
+ return FALSE;
}
- else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
- return FALSE;
} else {
/*
* If we're compiling for shared code
if (mono_method_has_declsec (method))
return FALSE;
- /* also consider num_locals? */
- if (getenv ("MONO_INLINELIMIT")) {
- if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
- return TRUE;
- }
- } else if (header->code_size < INLINE_LENGTH_LIMIT)
- return TRUE;
-
- return FALSE;
+ return TRUE;
}
static gboolean
MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
addr->inst_left = sp [0];
addr->inst_right = sp [1];
- addr->cil_code = ip;
addr->type = STACK_MP;
addr->klass = cmethod->klass->element_class;
return addr;
MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
addr->inst_left = sp [0];
addr->inst_right = indexes;
- addr->cil_code = ip;
addr->type = STACK_MP;
addr->klass = cmethod->klass->element_class;
return addr;
}
#endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
+#ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
+ /*
+ * Can't implement CompareExchange methods this way since they have
+ * three arguments. We can implement one of the common cases, where the new
+ * value is a constant.
+ */
+ if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
+ if (fsig->params [1]->type == MONO_TYPE_I4 && args [2]->opcode == OP_ICONST) {
+ MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
+ ins->inst_i0 = args [0];
+ ins->inst_i1 = args [1];
+ ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
+ }
+ /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
+ }
+#endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
+
if (ins)
return ins;
} else if (cmethod->klass->image == mono_defaults.corlib) {
}
static inline MonoMethod *
-mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
+mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
{
MonoMethod *method;
return method;
}
+static inline MonoMethod *
+mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
+{
+ MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
+
+ if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
+ return NULL;
+
+ return method;
+}
+
static inline MonoClass*
mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
{
if (newarr->inst_newa_len->opcode != OP_ICONST)
return NULL;
- cmethod = mini_get_method (method, token, NULL, NULL);
+ cmethod = mini_get_method (NULL, method, token, NULL, NULL);
if (!cmethod)
return NULL;
if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
{
char *method_fname = mono_method_full_name (method, TRUE);
- char *method_code = mono_disasm_code_one (NULL, method, ip, NULL);
+ char *method_code;
+
+ if (mono_method_get_header (method)->code_size == 0)
+ method_code = g_strdup ("method body is empty.");
+ else
+ method_code = mono_disasm_code_one (NULL, method, ip, NULL);
cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
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);
}
-/*
- * Generates this->vtable->runtime_generic_context
- */
-static MonoInst*
-get_runtime_generic_context_from_this (MonoCompile *cfg, MonoInst *this, unsigned char *ip)
-{
- MonoInst *vtable, *rgc_ptr_addr, *rgc_ptr_offset, *rgc_ptr;
-
- MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
- vtable->cil_code = ip;
- vtable->inst_left = this;
- vtable->type = STACK_PTR;
-
- NEW_ICONST (cfg, rgc_ptr_offset, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
-
- MONO_INST_NEW (cfg, rgc_ptr_addr, OP_PADD);
- rgc_ptr_addr->cil_code = ip;
- rgc_ptr_addr->inst_left = vtable;
- rgc_ptr_addr->inst_right = rgc_ptr_offset;
- rgc_ptr_addr->type = STACK_PTR;
-
- MONO_INST_NEW (cfg, rgc_ptr, CEE_LDIND_I);
- rgc_ptr->cil_code = ip;
- rgc_ptr->inst_left = rgc_ptr_addr;
- rgc_ptr->type = STACK_PTR;
-
- return rgc_ptr;
-}
-
static MonoInst*
get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, MonoInst *this, unsigned char *ip)
{
g_assert (!method->klass->valuetype);
if (method->flags & METHOD_ATTRIBUTE_STATIC) {
- MonoInst *rgctx_loc, *rgctx_var;
+ MonoInst *vtable_loc, *vtable_var;
- rgctx_loc = mono_get_rgctx_var (cfg);
- NEW_TEMPLOAD (cfg, rgctx_var, rgctx_loc->inst_c0);
+ vtable_loc = mono_get_vtable_var (cfg);
+ NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
- return rgctx_var;
+ return vtable_var;
} else {
- return get_runtime_generic_context_from_this (cfg, this, ip);
+ MonoInst *vtable;
+
+ MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
+ vtable->inst_left = this;
+ vtable->type = STACK_PTR;
+
+ return vtable;
}
}
static gpointer
create_rgctx_lazy_fetch_trampoline (guint32 offset)
{
+ static gboolean inited = FALSE;
+ static int num_trampolines = 0;
+
gpointer tramp, ptr;
mono_jit_lock ();
g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
mono_jit_unlock ();
+ if (!inited) {
+ mono_counters_register ("RGCTX num lazy fetch trampolines",
+ MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
+ inited = TRUE;
+ }
+ num_trampolines++;
+
return ptr;
-}
+}
+/*
+ * Generates rgc->other_infos [index].XXX if index is non-negative, or
+ * rgc->extra_other_infos [-index + 1] if index is negative. XXX is
+ * specified by rgctx_type;
+ */
static MonoInst*
-lazy_fetch_rgctx_direct_field (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *rgc_ptr, int offset, unsigned char *ip)
+get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
+ MonoInst *rgc_ptr, int slot, const unsigned char *ip)
{
MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
- guint8 *tramp = create_rgctx_lazy_fetch_trampoline (MONO_RGCTX_ENCODE_DIRECT_OFFSET (offset));
+ guint8 *tramp = create_rgctx_lazy_fetch_trampoline (slot);
int temp;
MonoInst *field;
- temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
+ temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
NEW_TEMPLOAD (cfg, field, temp);
}
static MonoInst*
-lazy_fetch_rgctx_indirect_field (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *rgc_ptr, int offset, unsigned char *ip)
+get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
+ MonoClass *klass, guint32 type_token, int token_source, MonoGenericContext *generic_context, MonoInst *rgctx,
+ int rgctx_type, unsigned char *ip)
{
- MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
- guint8 *tramp = create_rgctx_lazy_fetch_trampoline (MONO_RGCTX_ENCODE_INDIRECT_OFFSET (offset));
- int temp;
- MonoInst *field;
+ guint32 slot = mono_method_lookup_or_register_other_info (method,
+ FALSE, &klass->byval_arg, rgctx_type, generic_context);
- temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
+ return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
+}
- NEW_TEMPLOAD (cfg, field, temp);
+static MonoInst*
+get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
+ MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, const unsigned char *ip)
+{
+ guint32 slot = mono_method_lookup_or_register_other_info (method, FALSE, cmethod, rgctx_type, generic_context);
- return field;
+ return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
}
-/*
- * Generates ((MonoRuntimeGenericSuperInfo*)rgc)[-depth].XXX where XXX
- * is specified by rgctx_type.
- */
static MonoInst*
-get_runtime_generic_context_super_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
- MonoInst *rgc_ptr, int depth, int rgctx_type, unsigned char *ip)
+get_runtime_generic_context_field (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
+ MonoClassField *field, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type,
+ const unsigned char *ip)
{
- int field_offset_const, offset;
+ guint32 slot = mono_method_lookup_or_register_other_info (method, FALSE, field, rgctx_type, generic_context);
- g_assert (depth >= 1);
-
- switch (rgctx_type) {
- case MONO_RGCTX_INFO_STATIC_DATA :
- field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, static_data);
- break;
- case MONO_RGCTX_INFO_KLASS :
- field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, klass);
- break;
- case MONO_RGCTX_INFO_VTABLE:
- field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, vtable);
- break;
- default :
- g_assert_not_reached ();
- }
+ return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
+}
- offset = -depth * sizeof (MonoRuntimeGenericSuperInfo) + field_offset_const;
+static gboolean
+generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
+{
+ MonoType *type;
- return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, offset, ip);
+ if (cfg->generic_sharing_context)
+ type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
+ else
+ type = &klass->byval_arg;
+ return MONO_TYPE_IS_REFERENCE (type);
}
+/**
+ * Handles unbox of a Nullable<T>, returning a temp variable where the
+ * result is stored. If a rgctx is passed, then shared generic code
+ * is generated.
+ */
static int
-get_rgctx_arg_info_field_offset (int rgctx_type)
-{
- switch (rgctx_type) {
- case MONO_RGCTX_INFO_STATIC_DATA :
- return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, static_data);
- case MONO_RGCTX_INFO_KLASS:
- return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, klass);
- case MONO_RGCTX_INFO_VTABLE :
- return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, vtable);
- default:
- g_assert_not_reached ();
+handle_unbox_nullable (MonoCompile* cfg, MonoMethod *caller_method, MonoBasicBlock* bblock, MonoInst* val,
+ guchar *ip, MonoClass* klass, MonoGenericContext *generic_context, MonoInst *rgctx)
+{
+ MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
+ MonoMethodSignature *signature = mono_method_signature (method);
+
+ if (rgctx) {
+ MonoInst *addr = get_runtime_generic_context_method (cfg, caller_method, bblock, method,
+ generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
+
+ return mono_emit_rgctx_calli_spilled (cfg, bblock, signature, &val, addr, NULL, ip);
+ } else {
+ return mono_emit_method_call_spilled (cfg, bblock, method, signature, &val, ip, NULL);
}
}
-/*
- * Generates rgc->arg_infos [arg_num].XXX where XXX is specified by
- * rgctx_type;
- */
static MonoInst*
-get_runtime_generic_context_arg_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
- MonoInst *rgc_ptr, int arg_num, int rgctx_type, unsigned char *ip)
+handle_box_nullable_from_inst (MonoCompile *cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock *bblock,
+ MonoInst *val, const guchar *ip, MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx)
{
- int arg_info_offset, arg_info_field_offset, offset;
+ MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
+ MonoInst *dest, *method_addr;
+ int temp;
- g_assert (arg_num >= 0);
- //g_assert (!lazy);
+ g_assert (mono_class_is_nullable (klass));
- arg_info_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, arg_infos) +
- arg_num * sizeof (MonoRuntimeGenericArgInfo);
+ method_addr = get_runtime_generic_context_method (cfg, caller_method, bblock, method,
+ generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
+ temp = mono_emit_rgctx_calli_spilled (cfg, bblock, mono_method_signature (method), &val,
+ method_addr, NULL, ip);
+ NEW_TEMPLOAD (cfg, dest, temp);
+ return dest;
+}
- arg_info_field_offset = get_rgctx_arg_info_field_offset (rgctx_type);
+static MonoObject*
+mono_object_castclass (MonoObject *obj, MonoClass *klass)
+{
+ if (!obj)
+ return NULL;
- offset = arg_info_offset + arg_info_field_offset;
+ if (mono_object_isinst (obj, klass))
+ return obj;
- return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, offset, ip);
-}
+ mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
+ "System", "InvalidCastException"));
-/*
- * Generates rgc->other_infos [index].XXX if index is non-negative, or
- * rgc->extra_other_infos [-index + 1] if index is negative. XXX is
- * specified by rgctx_type;
- */
-static MonoInst*
-get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
- MonoInst *rgc_ptr, int index, unsigned char *ip)
-{
- if (index < MONO_RGCTX_MAX_OTHER_INFOS) {
- int other_type_offset;
+ return NULL;
+}
- other_type_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, other_infos) +
- index * sizeof (gpointer);
+static int
+emit_castclass (MonoClass *klass, guint32 token, gboolean shared_access, gboolean inst_is_castclass, MonoCompile *cfg,
+ MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
+ unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
+ MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
+{
+ MonoBasicBlock *bblock = *_bblock;
+ unsigned char *ip = *_ip;
+ MonoInst **sp = *_sp;
+ int inline_costs = *_inline_costs;
+ guint real_offset = *_real_offset;
+ int return_value = 0;
+
+ if (shared_access) {
+ MonoInst *this = NULL, *rgctx;
+ MonoInst *args [2];
+ int temp;
- return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, other_type_offset, ip);
- } else {
- int slot_offset;
+ g_assert (!method->klass->valuetype);
- slot_offset = (index - MONO_RGCTX_MAX_OTHER_INFOS) * sizeof (gpointer);
+ /* obj */
+ args [0] = *sp;
- return lazy_fetch_rgctx_indirect_field (cfg, bblock, rgc_ptr, slot_offset, ip);
- }
-}
+ /* klass */
+ if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
+ NEW_ARGLOAD (cfg, this, 0);
+ rgctx = get_runtime_generic_context (cfg, method, this, ip);
+ args [1] = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
+ token, MINI_TOKEN_SOURCE_CLASS, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
-static MonoInst*
-get_runtime_generic_context_other_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
- MonoInst *rgc_ptr, guint32 token, int token_source, int rgctx_type, unsigned char *ip, int index)
-{
- MonoInst *args [6];
- int temp;
- MonoInst *result;
+ temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass, args, ip);
+ NEW_TEMPLOAD (cfg, *sp, temp);
- g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
+ sp++;
+ ip += 5;
+ inline_costs += 2;
+ } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
- NEW_CLASSCONST (cfg, args [0], method->klass);
- args [1] = rgc_ptr;
- NEW_ICONST (cfg, args [2], token);
- NEW_ICONST (cfg, args [3], token_source);
- NEW_ICONST (cfg, args [4], rgctx_type);
- NEW_ICONST (cfg, args [5], index);
+ MonoMethod *mono_castclass;
+ MonoInst *iargs [1];
+ MonoBasicBlock *ebblock;
+ int costs;
+ int temp;
- temp = mono_emit_jit_icall (cfg, bblock, mono_helper_get_rgctx_other_ptr, args, ip);
- NEW_TEMPLOAD (cfg, result, temp);
+ mono_castclass = mono_marshal_get_castclass (klass);
+ iargs [0] = sp [0];
- return result;
-}
+ costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
+ iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
-static MonoInst*
-get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
- MonoClass *klass, guint32 type_token, int token_source, MonoGenericContext *generic_context, MonoInst *rgctx,
- int rgctx_type, unsigned char *ip)
-{
- int arg_num = -1;
- int relation = mono_class_generic_class_relation (klass, rgctx_type, method->klass, generic_context, &arg_num);
-
- switch (relation) {
- case MINI_GENERIC_CLASS_RELATION_SELF: {
- int depth = klass->idepth;
- return get_runtime_generic_context_super_ptr (cfg, bblock, rgctx, depth, rgctx_type, ip);
- }
- case MINI_GENERIC_CLASS_RELATION_ARGUMENT:
- return get_runtime_generic_context_arg_ptr (cfg, bblock, rgctx, arg_num, rgctx_type, ip);
- case MINI_GENERIC_CLASS_RELATION_OTHER_TABLE:
- return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
- case MINI_GENERIC_CLASS_RELATION_OTHER:
- return get_runtime_generic_context_other_ptr (cfg, method, bblock, rgctx,
- type_token, token_source, rgctx_type, ip, arg_num);
- default:
- g_assert_not_reached ();
- return NULL;
- }
-}
+ g_assert (costs > 0);
-static MonoInst*
-get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
- MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, unsigned char *ip)
-{
- int arg_num = mono_class_lookup_or_register_other_info (method->klass, cmethod, rgctx_type, generic_context);
+ ip += 5;
+ real_offset += 5;
- return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
-}
+ GET_BBLOCK (cfg, bblock, ip);
+ ebblock->next_bb = bblock;
+ link_bblock (cfg, ebblock, bblock);
-static gboolean
-generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
-{
- MonoType *type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
+ temp = iargs [0]->inst_i0->inst_c0;
+ NEW_TEMPLOAD (cfg, *sp, temp);
- return MONO_TYPE_IS_REFERENCE (type);
-}
+ sp++;
+ bblock = ebblock;
+ inline_costs += costs;
+ } else {
+ MonoInst *ins;
-static MiniVerifierMode verifier_mode = MINI_VERIFIER_MODE_OFF;
+ /* Needed by the code generated in inssel.brg */
+ mono_get_got_var (cfg);
-void
-mini_verifier_set_mode (MiniVerifierMode mode)
-{
- verifier_mode = mode;
-}
+ MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
+ ins->type = STACK_OBJ;
+ ins->inst_left = *sp;
+ ins->klass = klass;
+ ins->inst_newa_class = klass;
+ if (inst_is_castclass)
+ ins->backend.record_cast_details = debug_options.better_cast_details;
+ if (inst_is_castclass)
+ *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
+ else
+ *sp++ = ins;
+ ip += 5;
+ }
-/*
- * Return TRUE if method don't need to be verifiable.
- * TODO check appdomain security flags
- */
-static gboolean
-check_method_full_trust (MonoMethod *method)
-{
- if (mono_verify_all)
- return verifier_mode < MINI_VERIFIER_MODE_VERIFIABLE;
- else
- return method->klass->image->assembly->in_gac || method->klass->image == mono_defaults.corlib || verifier_mode < MINI_VERIFIER_MODE_VERIFIABLE;
+do_return:
+ *_bblock = bblock;
+ *_ip = ip;
+ *_sp = sp;
+ *_inline_costs = inline_costs;
+ *_real_offset = real_offset;
+ return return_value;
+unverified:
+ return_value = -1;
+ goto do_return;
}
-/*
- * Return TRUE if method should be verifier
- * FIXME we should be able to check gac'ed code for validity
- */
static gboolean
-check_for_method_verify (MonoMethod *method)
+mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
{
- if (mono_verify_all)
- return method->wrapper_type == MONO_WRAPPER_NONE;
- else
- return (verifier_mode > MINI_VERIFIER_MODE_OFF) && !method->klass->image->assembly->in_gac && method->klass->image != mono_defaults.corlib && method->wrapper_type == MONO_WRAPPER_NONE;
+ MonoAssembly *assembly = method->klass->image->assembly;
+ if (method->wrapper_type != MONO_WRAPPER_NONE)
+ return FALSE;
+ if (assembly->in_gac || assembly->image == mono_defaults.corlib)
+ return FALSE;
+ if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE)
+ return FALSE;
+ return mono_assembly_has_skip_verification (assembly);
}
/*
mini_method_verify (MonoCompile *cfg, MonoMethod *method)
{
GSList *tmp, *res;
- gboolean is_fulltrust = check_method_full_trust (method);
+ gboolean is_fulltrust;
MonoLoaderError *error;
- if (!check_for_method_verify (method))
+ if (method->verification_success)
return FALSE;
- res = mono_method_verify (method,
- (verifier_mode != MINI_VERIFIER_MODE_STRICT ? MONO_VERIFY_NON_STRICT: 0)
- | (!is_fulltrust ? MONO_VERIFY_FAIL_FAST : 0)
- | (cfg->skip_visibility ? MONO_VERIFY_SKIP_VISIBILITY : 0));
+ is_fulltrust = mono_verifier_is_method_full_trust (method);
+
+ if (!mono_verifier_is_enabled_for_method (method))
+ return FALSE;
+
+ res = mono_method_verify_with_current_settings (method, cfg->skip_visibility);
if ((error = mono_loader_get_last_error ())) {
cfg->exception_type = error->exception_type;
}
mono_free_verify_list (res);
}
+ method->verification_success = 1;
return FALSE;
}
MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
MonoInst *ins, **sp, **stack_start;
MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
- MonoMethod *cmethod;
+ MonoMethod *cmethod, *method_definition;
MonoInst **arg_array;
MonoMethodHeader *header;
MonoImage *image;
image = method->klass->image;
header = mono_method_get_header (method);
- generic_container = method->generic_container;
+ generic_container = mono_method_get_generic_container (method);
sig = mono_method_signature (method);
num_args = sig->hasthis + sig->param_count;
ip = (unsigned char*)header->code;
end = ip + header->code_size;
mono_jit_stats.cil_code_size += header->code_size;
- if (!dont_verify && mini_method_verify (cfg, method))
+ method_definition = method;
+ while (method_definition->is_inflated) {
+ MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
+ method_definition = imethod->declaring;
+ }
+
+ /* SkipVerification is not allowed if core-clr is enabled */
+ if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
+ dont_verify = TRUE;
+ dont_verify_stloc = TRUE;
+ }
+
+ if (!dont_verify && mini_method_verify (cfg, method_definition))
goto exception_exit;
if (sig->is_inflated)
MonoBasicBlock *try_bb;
MonoExceptionClause *clause = &header->clauses [i];
- if ((method->flags & METHOD_ATTRIBUTE_STATIC) &&
- clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
- clause->data.catch_class &&
- cfg->generic_sharing_context &&
- mono_class_check_context_used (clause->data.catch_class)) {
- mono_get_rgctx_var (cfg);
- }
-
GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
try_bb->real_offset = clause->try_offset;
GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
MONO_ADD_INS (tblock, ins);
}
}
+
+ if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
+ clause->data.catch_class &&
+ cfg->generic_sharing_context &&
+ mono_class_check_context_used (clause->data.catch_class)) {
+ /*
+ * In shared generic code with catch
+ * clauses containing type variables
+ * the exception handling code has to
+ * be able to get to the rgctx.
+ * Therefore we have to make sure that
+ * the rgctx argument (for static
+ * methods) or the "this" argument
+ * (for non-static methods) are live.
+ */
+ if (method->flags & METHOD_ATTRIBUTE_STATIC) {
+ mono_get_vtable_var (cfg);
+ } else {
+ MonoInst *this, *dummy_use;
+ MonoType *this_type;
+
+ if (method->klass->valuetype)
+ this_type = &method->klass->this_arg;
+ else
+ this_type = &method->klass->byval_arg;
+
+ if (arg_array [0]->opcode == OP_ICONST) {
+ this = arg_array [0];
+ } else {
+ this = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));
+ this->ssa_op = MONO_SSA_LOAD;
+ this->inst_i0 = arg_array [0];
+ this->opcode = mini_type_to_ldind ((cfg), this->inst_i0->inst_vtype);
+ type_to_eval_stack_type ((cfg), this_type, this);
+ this->klass = this->inst_i0->klass;
+ }
+
+ NEW_DUMMY_USE (cfg, dummy_use, this);
+ MONO_ADD_INS (tblock, dummy_use);
+ }
+ }
}
} else {
arg_array = alloca (sizeof (MonoInst *) * num_args);
real_offset = ip - header->code;
else
real_offset = inline_offset;
+ cfg->ip = ip;
if (start_new_bblock) {
bblock->cil_length = ip - bblock->cil_code;
ins->cil_code = ip;
MONO_INST_NEW (cfg, store, CEE_STIND_I);
- store->cil_code = ip;
store->inst_left = ins;
store->inst_right = one;
switch (*ip) {
case CEE_NOP:
MONO_INST_NEW (cfg, ins, OP_NOP);
- ins->cil_code = ip++;
+ ip++;
MONO_ADD_INS (bblock, ins);
break;
case CEE_BREAK:
MONO_INST_NEW (cfg, ins, OP_BREAK);
- ins->cil_code = ip++;
+ ip++;
MONO_ADD_INS (bblock, ins);
break;
case CEE_LDARG_0:
CHECK_ARG (n);
NEW_ARGLOAD (cfg, ins, n);
LDARG_SOFT_FLOAT (cfg, ins, n, ip);
- ins->cil_code = ip++;
+ ip++;
*sp++ = ins;
break;
case CEE_LDLOC_0:
CHECK_LOCAL (n);
NEW_LOCLOAD (cfg, ins, n);
LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
- ins->cil_code = ip++;
+ ip++;
*sp++ = ins;
break;
case CEE_STLOC_0:
--sp;
handle_loaded_temps (cfg, bblock, stack_start, sp);
NEW_LOCSTORE (cfg, ins, n, *sp);
- ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
UNVERIFIED;
STLOC_SOFT_FLOAT (cfg, ins, n, ip);
CHECK_ARG (ip [1]);
NEW_ARGLOAD (cfg, ins, ip [1]);
LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
- ins->cil_code = ip;
*sp++ = ins;
ip += 2;
break;
CHECK_STACK_OVF (1);
CHECK_ARG (ip [1]);
NEW_ARGLOADA (cfg, ins, ip [1]);
- ins->cil_code = ip;
*sp++ = ins;
ip += 2;
break;
CHECK_ARG (ip [1]);
NEW_ARGSTORE (cfg, ins, ip [1], *sp);
handle_loaded_temps (cfg, bblock, stack_start, sp);
- ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
UNVERIFIED;
STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
CHECK_LOCAL (ip [1]);
NEW_LOCLOAD (cfg, ins, ip [1]);
LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
- ins->cil_code = ip;
*sp++ = ins;
ip += 2;
break;
CHECK_STACK_OVF (1);
CHECK_LOCAL (ip [1]);
NEW_LOCLOADA (cfg, ins, ip [1]);
- ins->cil_code = ip;
*sp++ = ins;
ip += 2;
break;
handle_loaded_temps (cfg, bblock, stack_start, sp);
CHECK_LOCAL (ip [1]);
NEW_LOCSTORE (cfg, ins, ip [1], *sp);
- ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
UNVERIFIED;
STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
case CEE_LDNULL:
CHECK_STACK_OVF (1);
NEW_PCONST (cfg, ins, NULL);
- ins->cil_code = ip;
ins->type = STACK_OBJ;
++ip;
*sp++ = ins;
case CEE_LDC_I4_M1:
CHECK_STACK_OVF (1);
NEW_ICONST (cfg, ins, -1);
- ins->cil_code = ip;
++ip;
*sp++ = ins;
break;
case CEE_LDC_I4_8:
CHECK_STACK_OVF (1);
NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
- ins->cil_code = ip;
++ip;
*sp++ = ins;
break;
CHECK_STACK_OVF (1);
++ip;
NEW_ICONST (cfg, ins, *((signed char*)ip));
- ins->cil_code = ip;
++ip;
*sp++ = ins;
break;
CHECK_OPSIZE (5);
CHECK_STACK_OVF (1);
NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
- ins->cil_code = ip;
ip += 5;
*sp++ = ins;
break;
CHECK_OPSIZE (9);
CHECK_STACK_OVF (1);
MONO_INST_NEW (cfg, ins, OP_I8CONST);
- ins->cil_code = ip;
ins->type = STACK_I8;
++ip;
ins->inst_l = (gint64)read64 (ip);
sp++;
MONO_INST_NEW (cfg, temp, 0);
*temp = *ins;
- temp->cil_code = ip;
*sp++ = temp;
} else {
temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
temp->flags |= MONO_INST_IS_TEMP;
- temp->cil_code = ip;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
- store->cil_code = ip;
/* FIXME: handle CEE_STIND_R4 */
if (store->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, store, temp->inst_c0);
}
NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
*sp++ = ins;
- ins->cil_code = ip;
NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
*sp++ = ins;
- ins->cil_code = ip;
}
++ip;
inline_costs += 2;
CHECK_STACK (1);
MONO_INST_NEW (cfg, ins, CEE_POP);
MONO_ADD_INS (bblock, ins);
- ins->cil_code = ip++;
+ ip++;
--sp;
ins->inst_i0 = *sp;
break;
MONO_INST_NEW (cfg, ins, OP_JMP);
token = read32 (ip + 1);
/* FIXME: check the signature matches */
- cmethod = mini_get_method (method, token, NULL, generic_context);
+ cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
if (!cmethod)
goto load_error;
MonoMethodSignature *fsig = NULL;
int temp, array_rank = 0;
int virtual = *ip == CEE_CALLVIRT;
- MonoInst *rgctx_arg = NULL;
gboolean no_spill;
int context_used = 0;
- gboolean pass_rgctx = FALSE;
+ gboolean pass_imt_from_rgctx = FALSE;
+ MonoInst *imt_arg = NULL;
+ gboolean pass_vtable = FALSE;
+ MonoInst *vtable_arg = NULL;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
cil_method = cmethod;
} else {
- cmethod = mini_get_method (method, token, NULL, generic_context);
+ cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
cil_method = cmethod;
}
if (!cmethod)
goto load_error;
- if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cil_method))
- METHOD_ACCESS_FAILURE;
+ if (!dont_verify && !cfg->skip_visibility) {
+ MonoMethod *target_method = cil_method;
+ if (method->is_inflated) {
+ target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
+ }
+ if (!mono_method_can_access_method (method_definition, target_method) &&
+ !mono_method_can_access_method (method, cil_method))
+ METHOD_ACCESS_FAILURE;
+ }
if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
*/
MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
- load->cil_code = ip;
load->inst_left = sp [0];
sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
} else if (!constrained_call->valuetype) {
*/
MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
- ins->cil_code = ip;
ins->inst_i0 = sp [0];
ins->type = STACK_OBJ;
ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
/*
- * Pass rgctx iff target method might
+ * Pass vtable iff target method might
* be shared, which means that sharing
* is enabled for its class and its
* context is sharable (and it's not a
* generic method).
*/
- if (sharing_enabled && context_sharable &&
- !mini_method_get_context (cmethod)->method_inst)
- pass_rgctx = TRUE;
+ if (sharing_enabled && context_sharable)
+ pass_vtable = TRUE;
}
if (cfg->generic_sharing_context && cmethod) {
if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
GENERIC_SHARING_FAILURE (*ip);
+ if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ /* Generic method interface
+ calls are resolved via a
+ helper function and don't
+ need an imt. */
+ if (!cmethod_context || !cmethod_context->method_inst)
+ pass_imt_from_rgctx = TRUE;
+ }
if (context_used &&
- ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) ||
- (cmethod_context && cmethod_context->method_inst && cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
+ (cmethod_context && cmethod_context->method_inst && cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
GENERIC_SHARING_FAILURE (*ip);
}
}
- if (pass_rgctx) {
+ if (pass_vtable) {
if (context_used) {
- MonoInst *this = NULL, *rgctx, *vtable, *field_offset, *field_addr;
-
- GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
+ MonoInst *rgctx;
- if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
- NEW_ARGLOAD (cfg, this, 0);
- rgctx = get_runtime_generic_context (cfg, method, this, ip);
- vtable = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
+ GET_RGCTX (rgctx);
+ vtable_arg = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
token, MINI_TOKEN_SOURCE_METHOD, generic_context,
rgctx, MONO_RGCTX_INFO_VTABLE, ip);
-
- NEW_ICONST (cfg, field_offset, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
-
- MONO_INST_NEW (cfg, field_addr, OP_PADD);
- field_addr->cil_code = ip;
- field_addr->inst_left = vtable;
- field_addr->inst_right = field_offset;
- field_addr->type = STACK_PTR;
-
- MONO_INST_NEW (cfg, rgctx_arg, CEE_LDIND_I);
- rgctx_arg->cil_code = ip;
- rgctx_arg->inst_left = field_addr;
- rgctx_arg->type = STACK_PTR;
} else {
MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
-
- NEW_PCONST (cfg, rgctx_arg, vtable->runtime_generic_context);
+
+ CHECK_TYPELOAD (cmethod->klass);
+ NEW_VTABLECONST (cfg, vtable_arg, vtable);
}
}
+ if (pass_imt_from_rgctx) {
+ MonoInst *rgctx;
+
+ g_assert (!pass_vtable);
+ g_assert (cmethod);
+
+ GET_RGCTX (rgctx);
+ imt_arg = get_runtime_generic_context_method (cfg, method, bblock, cmethod,
+ generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+ }
+
if (cmethod && virtual &&
(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
!((cmethod->flags & METHOD_ATTRIBUTE_FINAL) &&
INLINE_FAILURE;
this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
- this_temp->cil_code = ip;
NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
-
- store->cil_code = ip;
MONO_ADD_INS (bblock, store);
/* FIXME: This should be a managed pointer */
this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- this_arg_temp->cil_code = ip;
/* Because of the PCONST below */
cfg->disable_aot = TRUE;
NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
- NEW_METHODCONST (cfg, iargs [1], cmethod);
- NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
- NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
- temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
+ if (context_used) {
+ MonoInst *rgctx;
+
+ GET_RGCTX (rgctx);
+ iargs [1] = get_runtime_generic_context_method (cfg, method, bblock, cmethod,
+ generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+ NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
+ temp = mono_emit_jit_icall (cfg, bblock,
+ mono_helper_compile_generic_method_wo_context, iargs, ip);
+ } else {
+ NEW_METHODCONST (cfg, iargs [1], cmethod);
+ NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
+ NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
+ temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method,
+ iargs, ip);
+ }
NEW_TEMPLOAD (cfg, addr, temp);
NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
}
/* FIXME: runtime generic context pointer for jumps? */
- if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
+ if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
(mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
int i;
continue;
NEW_ARGSTORE (cfg, ins, i, sp [i]);
- ins->cil_code = ip;
/* FIXME: handle CEE_STIND_R4 */
if (ins->opcode == CEE_STOBJ) {
NEW_ARGLOADA (cfg, ins, i);
MONO_ADD_INS (bblock, ins);
}
MONO_INST_NEW (cfg, ins, OP_JMP);
- ins->cil_code = ip;
ins->inst_p0 = cmethod;
ins->inst_p1 = arg_array [0];
MONO_ADD_INS (bblock, ins);
break;
}
if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
- ins->cil_code = ip;
-
if (MONO_TYPE_IS_VOID (fsig->ret)) {
MONO_ADD_INS (bblock, ins);
} else {
/* tail recursion elimination */
if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET &&
- !rgctx_arg) {
+ !vtable_arg) {
gboolean has_vtargs = FALSE;
int i;
for (i = 0; i < n; ++i) {
/* FIXME: handle CEE_STIND_R4 */
NEW_ARGSTORE (cfg, ins, i, sp [i]);
- ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
}
MONO_INST_NEW (cfg, ins, OP_BR);
- ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
tblock = start_bblock->out_bb [0];
link_bblock (cfg, bblock, tblock);
else
no_spill = FALSE;
+ /* FIXME: only do this for generic methods if
+ they are not shared! */
if (context_used &&
(cmethod->klass->valuetype ||
(cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) ||
((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
- mono_class_generic_sharing_enabled (cmethod->klass)))) {
- MonoInst *this = NULL, *rgctx;
+ mono_class_generic_sharing_enabled (cmethod->klass)) ||
+ (!imt_arg && !mono_method_is_generic_sharable_impl (cmethod) &&
+ (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
+ !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))))) {
+ MonoInst *rgctx;
INLINE_FAILURE;
g_assert (cfg->generic_sharing_context && cmethod);
- g_assert (addr == NULL);
+ g_assert (!addr);
/*
- * We are compiling a call to a
- * generic method from shared code,
- * which means that we have to look up
- * the method in the rgctx and do an
- * indirect call.
+ * We are compiling a call to
+ * non-shared generic code from shared
+ * code, which means that we have to
+ * look up the method in the rgctx and
+ * do an indirect call.
*/
-
- GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
-
- if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
- NEW_ARGLOAD (cfg, this, 0);
- rgctx = get_runtime_generic_context (cfg, method, this, ip);
+ GET_RGCTX (rgctx);
addr = get_runtime_generic_context_method (cfg, method, bblock, cmethod,
generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
+
}
if (addr) {
- if (*ip == CEE_CALL)
+ g_assert (!imt_arg);
+
+ if (*ip == CEE_CALL) {
g_assert (context_used);
- else if (*ip == CEE_CALLI)
- g_assert (!rgctx_arg);
- else
- g_assert_not_reached ();
+ } else if (*ip == CEE_CALLI) {
+ g_assert (!vtable_arg);
+ } else {
+ g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
+ !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
+ }
/* Prevent inlining of methods with indirect calls */
INLINE_FAILURE;
if (no_spill) {
- ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, rgctx_arg, ip);
+ ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
*sp++ = ins;
} else {
- temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, rgctx_arg, ip);
+ temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
if (temp != -1) {
NEW_TEMPLOAD (cfg, *sp, temp);
sp++;
array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
- store->cil_code = ip;
MONO_ADD_INS (bblock, store);
NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
/* FIXME: handle CEE_STIND_R4 */
- store->cil_code = ip;
MONO_ADD_INS (bblock, store);
NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
- ins->cil_code = ip;
/* FIXME: handle CEE_STIND_R4 */
if (ins->opcode == CEE_STOBJ) {
handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
} else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
NEW_INDLOAD (cfg, ins, addr, fsig->ret);
- ins->cil_code = ip;
*sp++ = ins;
} else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
mono_get_got_var (cfg);
MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
- check->cil_code = ip;
check->klass = cmethod->klass;
check->inst_left = sp [0];
check->type = STACK_OBJ;
sp++;
}
} else if (no_spill) {
- ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp, rgctx_arg, ip, virtual ? sp [0] : NULL);
+ ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp,
+ vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL);
*sp++ = ins;
} else {
- if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp, rgctx_arg, ip, virtual ? sp [0] : NULL)) != -1) {
+ if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
+ vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL)) != -1) {
MonoInst *load;
NEW_TEMPLOAD (cfg, load, temp);
handle_stobj (cfg, bblock, ins, *sp, ip, cfg->ret->klass, FALSE, FALSE, FALSE);
} else {
ins->opcode = OP_SETRET;
- ins->cil_code = ip;
ins->inst_i0 = *sp;;
ins->inst_i1 = NULL;
MONO_ADD_INS (bblock, ins);
if (sp != stack_start)
UNVERIFIED;
MONO_INST_NEW (cfg, ins, OP_BR);
- ins->cil_code = ip++;
+ ip++;
ins->inst_target_bb = end_bblock;
MONO_ADD_INS (bblock, ins);
link_bblock (cfg, bblock, end_bblock);
case CEE_BR_S:
CHECK_OPSIZE (2);
MONO_INST_NEW (cfg, ins, OP_BR);
- ins->cil_code = ip++;
+ ip++;
MONO_ADD_INS (bblock, ins);
target = ip + 1 + (signed char)(*ip);
++ip;
if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
UNVERIFIED;
MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
- ins->cil_code = ip++;
+ ip++;
target = ip + 1 + *(signed char*)ip;
ip++;
ADD_UNCOND (ins->opcode == CEE_BRTRUE);
CHECK_OPSIZE (2);
CHECK_STACK (2);
MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
- ins->cil_code = ip++;
+ ip++;
target = ip + 1 + *(signed char*)ip;
ip++;
#ifdef MONO_ARCH_SOFT_FLOAT
case CEE_BR:
CHECK_OPSIZE (5);
MONO_INST_NEW (cfg, ins, OP_BR);
- ins->cil_code = ip++;
+ ip++;
MONO_ADD_INS (bblock, ins);
target = ip + 4 + (gint32)read32(ip);
ip += 4;
if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
UNVERIFIED;
MONO_INST_NEW (cfg, ins, *ip);
- ins->cil_code = ip++;
+ ip++;
target = ip + 4 + (gint32)read32(ip);
ip += 4;
ADD_UNCOND(ins->opcode == CEE_BRTRUE);
CHECK_OPSIZE (5);
CHECK_STACK (2);
MONO_INST_NEW (cfg, ins, *ip);
- ins->cil_code = ip++;
+ ip++;
target = ip + 4 + (gint32)read32(ip);
ip += 4;
#ifdef MONO_ARCH_SOFT_FLOAT
ins->inst_left = *sp;
if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR))
UNVERIFIED;
- ins->cil_code = ip;
ip += 5;
CHECK_OPSIZE (n * sizeof (guint32));
target = ip + n * sizeof (guint32);
case CEE_LDIND_REF:
CHECK_STACK (1);
MONO_INST_NEW (cfg, ins, *ip);
- ins->cil_code = ip;
--sp;
ins->inst_i0 = *sp;
*sp++ = ins;
}
#endif
MONO_INST_NEW (cfg, ins, *ip);
- ins->cil_code = ip++;
+ ip++;
sp -= 2;
handle_loaded_temps (cfg, bblock, stack_start, sp);
MONO_ADD_INS (bblock, ins);
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
sp -= 2;
- if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+ if (generic_class_is_reference_type (cfg, klass)) {
MonoInst *store, *load;
MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
- load->cil_code = ip;
load->inst_i0 = sp [1];
load->type = STACK_OBJ;
load->klass = klass;
load->flags |= ins_flag;
MONO_INST_NEW (cfg, store, CEE_STIND_REF);
- store->cil_code = ip;
handle_loaded_temps (cfg, bblock, stack_start, sp);
MONO_ADD_INS (bblock, store);
store->inst_i0 = sp [0];
iargs [0] = sp [0];
iargs [1] = sp [1];
NEW_ICONST (cfg, iargs [2], n);
- iargs [2]->cil_code = ip;
mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
}
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
- if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+ if (generic_class_is_reference_type (cfg, klass)) {
MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
- ins->cil_code = ip;
ins->inst_i0 = sp [0];
ins->type = STACK_OBJ;
ins->klass = klass;
/* FIXME: handle CEE_STIND_R4 */
if (ins->opcode == CEE_STOBJ) {
handle_loaded_temps (cfg, bblock, stack_start, sp);
- ins->cil_code = ip;
g_assert (ins->opcode == CEE_STOBJ);
NEW_LOCLOADA (cfg, ins, loc_index);
handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
MonoMethod *memcpy_method = get_memcpy_method ();
iargs [1] = *sp;
NEW_ICONST (cfg, iargs [2], n);
- iargs [2]->cil_code = ip;
mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
}
if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
/* FIXME: moving GC */
NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
- ins->cil_code = ip;
ins->type = STACK_OBJ;
ins->klass = mono_defaults.string_class;
*sp = ins;
}
else {
NEW_PCONST (cfg, ins, NULL);
- ins->cil_code = ip;
ins->type = STACK_OBJ;
ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
ins->klass = mono_defaults.string_class;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
- cmethod = mini_get_method (method, token, NULL, generic_context);
+ cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
if (!cmethod)
goto load_error;
fsig = mono_method_get_signature (cmethod, image, token);
* will be transformed into a normal call there.
*/
} else if (generic_shared) {
- MonoInst *this = NULL, *rgctx, *vtable;
+ MonoInst *rgctx, *data;
+ int rgctx_info;
- GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
-
- if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
- NEW_ARGLOAD (cfg, this, 0);
- rgctx = get_runtime_generic_context (cfg, method, this, ip);
- vtable = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
+ GET_RGCTX (rgctx);
+ if (cfg->opt & MONO_OPT_SHARED)
+ rgctx_info = MONO_RGCTX_INFO_KLASS;
+ else
+ rgctx_info = MONO_RGCTX_INFO_VTABLE;
+ data = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
token, MINI_TOKEN_SOURCE_METHOD, generic_context,
- rgctx, MONO_RGCTX_INFO_VTABLE, ip);
+ rgctx, rgctx_info, ip);
- temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, vtable, FALSE, ip);
+ temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, data, FALSE, ip);
NEW_TEMPLOAD (cfg, *sp, temp);
} else {
MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+
+ CHECK_TYPELOAD (cmethod->klass);
if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
guint8 *tramp = mono_create_class_init_trampoline (vtable);
mono_emit_native_call (cfg, bblock, tramp,
INLINE_FAILURE;
mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
}
- } else if (generic_shared && cmethod->klass->valuetype) {
+ } else if (generic_shared &&
+ (cmethod->klass->valuetype ||
+ !mono_method_is_generic_sharable_impl (cmethod))) {
MonoInst *this = NULL, *rgctx, *cmethod_addr;
g_assert (!callvirt_this_arg);
ins->inst_left = *sp;
ins->inst_newa_class = klass;
ins->klass = klass;
- ins->cil_code = ip;
*sp++ = emit_tree (cfg, bblock, ins, ip + 5);
ip += 5;
}
MonoInst *add, *vtoffset;
MonoInst *iargs [3];
guint32 align;
+ int context_used = 0;
CHECK_STACK (1);
--sp;
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
- if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
- GENERIC_SHARING_FAILURE (CEE_UNBOX_ANY);
+ if (cfg->generic_sharing_context) {
+ context_used = mono_class_check_context_used (klass);
- if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
- /* CASTCLASS */
- if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
- MonoMethod *mono_castclass;
- MonoInst *iargs [1];
- MonoBasicBlock *ebblock;
- int costs;
- int temp;
-
- mono_castclass = mono_marshal_get_castclass (klass);
- iargs [0] = sp [0];
-
- costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
- iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
-
- g_assert (costs > 0);
-
- ip += 5;
- real_offset += 5;
-
- GET_BBLOCK (cfg, bblock, ip);
- ebblock->next_bb = bblock;
- link_bblock (cfg, ebblock, bblock);
-
- temp = iargs [0]->inst_i0->inst_c0;
- NEW_TEMPLOAD (cfg, *sp, temp);
-
- sp++;
- bblock = ebblock;
- inline_costs += costs;
- } else {
- /* Needed by the code generated in inssel.brg */
- mono_get_got_var (cfg);
-
- MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
- ins->type = STACK_OBJ;
- ins->inst_left = *sp;
- ins->klass = klass;
- ins->inst_newa_class = klass;
- ins->cil_code = ip;
- *sp++ = ins;
- ip += 5;
+ if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
+ GENERIC_SHARING_FAILURE (CEE_UNBOX_ANY);
+ }
+
+ if (generic_class_is_reference_type (cfg, klass)) {
+ if (context_used)
+ GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (CEE_UNBOX_ANY);
+ switch (emit_castclass (klass, token, context_used, FALSE,
+ cfg, method, arg_array, param_types, dont_inline, end, header,
+ generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
+ case 0: break;
+ case -1: goto unverified;
+ default: g_assert_not_reached ();
}
break;
}
if (mono_class_is_nullable (klass)) {
- int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+ int v;
+ MonoInst *rgctx = NULL;
+
+ if (context_used) {
+ MonoInst *this = NULL;
+
+ if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
+ NEW_ARGLOAD (cfg, this, 0);
+ rgctx = get_runtime_generic_context (cfg, method, this, ip);
+ }
+
+ v = handle_unbox_nullable (cfg, method, bblock, *sp, ip, klass, generic_context, rgctx);
NEW_TEMPLOAD (cfg, *sp, v);
sp ++;
ip += 5;
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
- MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
- ins->type = STACK_OBJ;
- ins->inst_left = *sp;
- ins->klass = klass;
- ins->inst_newa_class = klass;
- ins->cil_code = ip;
+ if (context_used) {
+ MonoInst *this = NULL, *rgctx;
+ MonoInst *element_class;
+
+ GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (CEE_UNBOX_ANY);
+
+ /* This assertion is from the
+ unboxcast insn */
+ g_assert (klass->rank == 0);
+
+ if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
+ NEW_ARGLOAD (cfg, this, 0);
+ rgctx = get_runtime_generic_context (cfg, method, this, ip);
+ /* FIXME: Passing token here is
+ technically not correct, because we
+ don't use klass but
+ klass->element_class. Since it's
+ only used by code for debugging the
+ extensible runtime generic context
+ it's not a big deal. To be correct
+ we'd have to invent a new token
+ source. */
+ element_class = get_runtime_generic_context_ptr (cfg, method, bblock,
+ klass->element_class, token, MINI_TOKEN_SOURCE_CLASS,
+ generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
+
+ MONO_INST_NEW (cfg, ins, OP_UNBOXCAST_REG);
+ ins->type = STACK_OBJ;
+ ins->inst_left = *sp;
+ ins->inst_right = element_class;
+ ins->klass = klass;
+ } else {
+ MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
+ ins->type = STACK_OBJ;
+ ins->inst_left = *sp;
+ ins->klass = klass;
+ ins->inst_newa_class = klass;
+ }
MONO_INST_NEW (cfg, add, OP_PADD);
NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
MonoMethod *memcpy_method = get_memcpy_method ();
iargs [1] = *sp;
NEW_ICONST (cfg, iargs [2], n);
- iargs [2]->cil_code = ip;
mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
}
GENERIC_SHARING_FAILURE (CEE_UNBOX);
if (mono_class_is_nullable (klass)) {
- int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+ int v = handle_unbox_nullable (cfg, method, bblock, *sp, ip, klass, generic_context, NULL);
NEW_TEMPLOAD (cfg, *sp, v);
sp ++;
ip += 5;
ins->inst_left = *sp;
ins->klass = klass;
ins->inst_newa_class = klass;
- ins->cil_code = ip;
MONO_INST_NEW (cfg, add, OP_PADD);
NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
inline_costs += 2;
break;
}
- case CEE_CASTCLASS:
+ case CEE_CASTCLASS: {
+ gboolean shared_access = FALSE;
+
CHECK_STACK (1);
--sp;
- CHECK_OPSIZE (5);
- token = read32 (ip + 1);
- klass = mini_get_class (method, token, generic_context);
- CHECK_TYPELOAD (klass);
- if (sp [0]->type != STACK_OBJ)
- UNVERIFIED;
-
- if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
- GENERIC_SHARING_FAILURE (CEE_CASTCLASS);
-
- /* Needed by the code generated in inssel.brg */
- mono_get_got_var (cfg);
-
- if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-
- MonoMethod *mono_castclass;
- MonoInst *iargs [1];
- MonoBasicBlock *ebblock;
- int costs;
- int temp;
-
- mono_castclass = mono_marshal_get_castclass (klass);
- iargs [0] = sp [0];
-
- costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
- iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
-
- g_assert (costs > 0);
-
- ip += 5;
- real_offset += 5;
-
- GET_BBLOCK (cfg, bblock, ip);
- ebblock->next_bb = bblock;
- link_bblock (cfg, ebblock, bblock);
+ CHECK_OPSIZE (5);
+ token = read32 (ip + 1);
+ klass = mini_get_class (method, token, generic_context);
+ CHECK_TYPELOAD (klass);
+ if (sp [0]->type != STACK_OBJ)
+ UNVERIFIED;
- temp = iargs [0]->inst_i0->inst_c0;
- NEW_TEMPLOAD (cfg, *sp, temp);
-
- sp++;
- bblock = ebblock;
- inline_costs += costs;
- } else {
- MONO_INST_NEW (cfg, ins, *ip);
- ins->type = STACK_OBJ;
- ins->inst_left = *sp;
- ins->klass = klass;
- ins->inst_newa_class = klass;
- ins->cil_code = ip;
- *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
- ip += 5;
+ if (cfg->generic_sharing_context) {
+ int context_used = mono_class_check_context_used (klass);
+
+ if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
+ GENERIC_SHARING_FAILURE (CEE_CASTCLASS);
+
+ if (context_used) {
+ shared_access = TRUE;
+ GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
+ }
+ }
+
+ switch (emit_castclass (klass, token, shared_access, TRUE,
+ cfg, method, arg_array, param_types, dont_inline, end, header,
+ generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
+ case 0: break;
+ case -1: goto unverified;
+ default: g_assert_not_reached ();
}
break;
+ }
case CEE_THROW:
CHECK_STACK (1);
MONO_INST_NEW (cfg, ins, OP_THROW);
--sp;
ins->inst_left = *sp;
- ins->cil_code = ip++;
+ ip++;
bblock->out_of_line = TRUE;
MONO_ADD_INS (bblock, ins);
MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
}
#if HAVE_WRITE_BARRIERS
- } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF) {
+ } else 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_marshal_get_write_barrier ();
MonoInst *iargs [2];
NEW_ICONST (cfg, offset_ins, foffset);
MONO_INST_NEW (cfg, ins, OP_PADD);
- ins->cil_code = ip;
ins->inst_left = *sp;
ins->inst_right = offset_ins;
ins->type = STACK_MP;
} else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
NEW_ICONST (cfg, offset_ins, foffset);
MONO_INST_NEW (cfg, ins, OP_PADD);
- ins->cil_code = ip;
ins->inst_left = *sp;
ins->inst_right = offset_ins;
ins->type = STACK_MP;
MonoInst *store;
NEW_ICONST (cfg, offset_ins, foffset);
MONO_INST_NEW (cfg, ins, OP_PADD);
- ins->cil_code = ip;
ins->inst_left = *sp;
ins->inst_right = offset_ins;
ins->type = STACK_MP;
MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
- store->cil_code = ip;
store->inst_left = ins;
store->inst_right = sp [1];
handle_loaded_temps (cfg, bblock, stack_start, sp);
} else {
NEW_ICONST (cfg, offset_ins, foffset);
MONO_INST_NEW (cfg, ins, OP_PADD);
- ins->cil_code = ip;
ins->inst_left = *sp;
ins->inst_right = offset_ins;
ins->type = STACK_MP;
MonoInst *load;
MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
type_to_eval_stack_type (cfg, field->type, load);
- load->cil_code = ip;
load->inst_left = ins;
load->flags |= ins_flag;
ins_flag = 0;
MonoClassField *field;
gpointer addr = NULL;
gboolean shared_access = FALSE;
- int relation = 0;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass->valuetype)
GENERIC_SHARING_FAILURE (*ip);
- if (context_used) {
- relation = mono_class_generic_class_relation (klass, MONO_RGCTX_INFO_VTABLE,
- method->klass, generic_context, NULL);
+ if (context_used)
shared_access = TRUE;
- }
}
g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
/* The special_static_fields field is init'd in mono_class_vtable, so it needs
* to be called here.
*/
- if (!(cfg->opt & MONO_OPT_SHARED))
+ if (!(cfg->opt & MONO_OPT_SHARED)) {
mono_class_vtable (cfg->domain, klass);
+ CHECK_TYPELOAD (klass);
+ }
mono_domain_lock (cfg->domain);
if (cfg->domain->special_static_fields)
addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
mono_domain_unlock (cfg->domain);
- if (shared_access) {
+ if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
+ int temp;
+ MonoInst *iargs [2];
+ MonoInst *domain_var;
+
+ g_assert (field->parent);
+ /* avoid depending on undefined C behavior in sequence points */
+ domain_var = mono_get_domainvar (cfg);
+ NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
+ if (shared_access) {
+ MonoInst *rgctx;
+
+ GET_RGCTX (rgctx);
+ iargs [1] = get_runtime_generic_context_field (cfg, method, bblock, field,
+ generic_context, rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
+ } else {
+ NEW_FIELDCONST (cfg, iargs [1], field);
+ }
+ temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
+ NEW_TEMPLOAD (cfg, ins, temp);
+ } else if (shared_access) {
MonoInst *this, *rgctx, *static_data;
GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
if (mono_class_needs_cctor_run (klass, method)) {
MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
MonoCallInst *call;
- MonoInst *vtable;
+ MonoInst *vtable, *rgctx;
if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
NEW_ARGLOAD (cfg, this, 0);
else
this = NULL;
- if (relation == MINI_GENERIC_CLASS_RELATION_SELF && this) {
- MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
- vtable->cil_code = ip;
- vtable->inst_left = this;
- vtable->type = STACK_PTR;
- vtable->klass = klass;
- } else {
- MonoInst *rgctx = get_runtime_generic_context (cfg, method, this, ip);
-
- vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
+ rgctx = get_runtime_generic_context (cfg, method, this, ip);
+ vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
token, MINI_TOKEN_SOURCE_FIELD, generic_context,
rgctx, MONO_RGCTX_INFO_VTABLE, ip);
- }
call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
call->inst.opcode = OP_TRAMPCALL_VTABLE;
NEW_ICONST (cfg, field_offset, field->offset);
MONO_INST_NEW (cfg, ins, OP_PADD);
- ins->cil_code = ip;
ins->inst_left = static_data;
ins->inst_right = field_offset;
ins->type = STACK_PTR;
ins->klass = klass;
}
- } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
- int temp;
- MonoInst *iargs [2];
- MonoInst *domain_var;
-
- g_assert (field->parent);
- /* avoid depending on undefined C behavior in sequence points */
- domain_var = mono_get_domainvar (cfg);
- NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
- NEW_FIELDCONST (cfg, iargs [1], field);
- temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
- NEW_TEMPLOAD (cfg, ins, temp);
} else {
MonoVTable *vtable;
+
vtable = mono_class_vtable (cfg->domain, klass);
+ CHECK_TYPELOAD (klass);
if (!addr) {
if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
guint8 *tramp = mono_create_class_init_trampoline (vtable);
NEW_SFLDACONST (cfg, ins, field);
else
NEW_PCONST (cfg, ins, addr);
- ins->cil_code = ip;
} else {
/*
* insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
CHECK_STACK (1);
sp--;
MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
- store->cil_code = ip;
store->inst_left = ins;
store->inst_right = sp [0];
store->flags |= ins_flag;
} else {
gboolean is_const = FALSE;
MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+
+ CHECK_TYPELOAD (klass);
if (!shared_access && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) &&
vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
gpointer addr = (char*)vtable->data + field->offset;
CHECK_STACK_OVF (1);
MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
type_to_eval_stack_type (cfg, field->type, load);
- load->cil_code = ip;
load->inst_left = ins;
load->flags |= ins_flag;
#ifdef MONO_ARCH_SOFT_FLOAT
/* FIXME: should check item at sp [1] is compatible with the type of the store. */
MonoInst *store;
MONO_INST_NEW (cfg, store, n);
- store->cil_code = ip;
store->inst_left = sp [0];
store->inst_right = sp [1];
store->flags |= ins_flag;
break;
case CEE_BOX: {
MonoInst *val;
- gboolean generic_shared = FALSE;
+ int context_used = 0;
CHECK_STACK (1);
--sp;
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
- if (cfg->generic_sharing_context && mono_class_check_context_used (klass)) {
- if (mono_class_is_nullable (klass))
- GENERIC_SHARING_FAILURE (CEE_BOX);
- else
- generic_shared = TRUE;
+ if (cfg->generic_sharing_context) {
+ context_used = mono_class_check_context_used (klass);
+
+ if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
+ GENERIC_SHARING_FAILURE (*ip);
}
- if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) ||
- (generic_shared && generic_class_is_reference_type (cfg, klass))) {
+ if (generic_class_is_reference_type (cfg, klass)) {
*sp++ = val;
ip += 5;
break;
/*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
MONO_INST_NEW (cfg, ins, CEE_POP);
MONO_ADD_INS (bblock, ins);
- ins->cil_code = ip;
ins->inst_i0 = *sp;
ip += 5;
+ cfg->ip = ip;
MONO_INST_NEW (cfg, ins, OP_BR);
- ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
if (*ip == CEE_BRTRUE_S) {
CHECK_OPSIZE (2);
start_new_bblock = 1;
break;
}
- if (generic_shared) {
- MonoInst *this = NULL, *rgctx, *vtable;
+ if (context_used) {
+ MonoInst *rgctx;
- GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
+ if (mono_class_is_nullable (klass)) {
+ GET_RGCTX (rgctx);
+ *sp++ = handle_box_nullable_from_inst (cfg, method, context_used, bblock, val,
+ ip, klass, generic_context, rgctx);
+ } else {
+ MonoInst *data;
+ int rgctx_info;
- if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
- NEW_ARGLOAD (cfg, this, 0);
- rgctx = get_runtime_generic_context (cfg, method, this, ip);
- vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
- token, MINI_TOKEN_SOURCE_CLASS, generic_context,
- rgctx, MONO_RGCTX_INFO_VTABLE, ip);
+ GET_RGCTX (rgctx);
+ if (cfg->opt & MONO_OPT_SHARED)
+ rgctx_info = MONO_RGCTX_INFO_KLASS;
+ else
+ rgctx_info = MONO_RGCTX_INFO_VTABLE;
+ data = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
+ token, MINI_TOKEN_SOURCE_CLASS, generic_context,
+ rgctx, rgctx_info, ip);
- *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, vtable);
+ *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, data);
+ }
} else {
*sp++ = handle_box (cfg, bblock, val, ip, klass);
}
NEW_TEMPLOAD (cfg, ins, temp);
} else {
MONO_INST_NEW (cfg, ins, *ip);
- ins->cil_code = ip;
ins->inst_newa_class = klass;
ins->inst_newa_len = *sp;
ins->type = STACK_OBJ;
MONO_INST_NEW (cfg, add, OP_PADD);
add->inst_left = load;
add->inst_right = data_offset;
- add->cil_code = ip;
iargs [0] = add;
if (cfg->compile_aot) {
NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
MONO_INST_NEW (cfg, ins, *ip);
- ins->cil_code = ip++;
+ ip++;
ins->inst_left = *sp;
ins->type = STACK_PTR;
*sp++ = ins;
mono_get_got_var (cfg);
MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
- check->cil_code = ip;
check->klass = mono_array_class_get (klass, 1);
check->inst_left = sp [0];
check->type = STACK_OBJ;
readonly = FALSE;
mono_class_init (klass);
NEW_LDELEMA (cfg, ins, sp, klass);
- ins->cil_code = ip;
*sp++ = ins;
ip += 5;
break;
CHECK_TYPELOAD (klass);
mono_class_init (klass);
NEW_LDELEMA (cfg, load, sp, klass);
- load->cil_code = ip;
MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
- ins->cil_code = ip;
ins->inst_left = load;
*sp++ = ins;
type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
UNVERIFIED;
klass = array_access_to_klass (*ip, sp [0]);
NEW_LDELEMA (cfg, load, sp, klass);
- load->cil_code = ip;
#ifdef MONO_ARCH_SOFT_FLOAT
if (*ip == CEE_LDELEM_R4) {
int temp;
}
#endif
MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
- ins->cil_code = ip;
ins->inst_left = load;
*sp++ = ins;
ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
UNVERIFIED;
klass = array_access_to_klass (*ip, sp [0]);
NEW_LDELEMA (cfg, load, sp, klass);
- load->cil_code = ip;
#ifdef MONO_ARCH_SOFT_FLOAT
if (*ip == CEE_STELEM_R4) {
handle_store_float (cfg, bblock, load, sp [2], ip);
}
#endif
MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
- ins->cil_code = ip;
ins->inst_left = load;
ins->inst_right = sp [2];
++ip;
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
mono_class_init (klass);
- if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+ if (generic_class_is_reference_type (cfg, klass)) {
/* storing a NULL doesn't need any of the complex checks in stelemref */
if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
MonoInst *load;
NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
- load->cil_code = ip;
MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
- ins->cil_code = ip;
ins->inst_left = load;
ins->inst_right = sp [2];
MONO_ADD_INS (bblock, ins);
}
} else {
NEW_LDELEMA (cfg, load, sp, klass);
- load->cil_code = ip;
n = mini_type_to_stind (cfg, &klass->byval_arg);
/* FIXME: CEE_STIND_R4 */
handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
else {
MONO_INST_NEW (cfg, ins, n);
- ins->cil_code = ip;
ins->inst_left = load;
ins->inst_right = sp [2];
handle_loaded_temps (cfg, bblock, stack_start, sp);
if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
MonoInst *load;
NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
- load->cil_code = ip;
MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
- ins->cil_code = ip;
ins->inst_left = load;
ins->inst_right = sp [2];
MONO_ADD_INS (bblock, ins);
MONO_INST_NEW (cfg, ins, OP_CKFINITE);
- ins->cil_code = ip;
ins->inst_left = sp [-1];
temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
- store->cil_code = ip;
MONO_ADD_INS (bblock, store);
NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
++ip;
break;
}
- case CEE_REFANYVAL:
+ case CEE_REFANYVAL: {
+ int context_used = 0;
+
CHECK_STACK (1);
- MONO_INST_NEW (cfg, ins, *ip);
--sp;
CHECK_OPSIZE (5);
- klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+ token = read32 (ip + 1);
+ klass = mono_class_get_full (image, token, generic_context);
CHECK_TYPELOAD (klass);
mono_class_init (klass);
- ins->type = STACK_MP;
- ins->inst_left = *sp;
- ins->klass = klass;
- ins->inst_newa_class = klass;
- ins->cil_code = ip;
+
+ if (cfg->generic_sharing_context) {
+ context_used = mono_class_check_context_used (klass);
+ if (context_used && cfg->compile_aot)
+ GENERIC_SHARING_FAILURE (*ip);
+ }
+
+ if (context_used) {
+ MonoInst *rgctx;
+
+ MONO_INST_NEW (cfg, ins, OP_REFANYVAL_REG);
+ ins->type = STACK_MP;
+ ins->inst_left = *sp;
+ ins->klass = klass;
+
+ GET_RGCTX (rgctx);
+ ins->inst_right = get_runtime_generic_context_ptr (cfg, method,
+ bblock, klass,
+ token, MINI_TOKEN_SOURCE_CLASS, generic_context,
+ rgctx, MONO_RGCTX_INFO_KLASS, ip);
+ } else {
+ MONO_INST_NEW (cfg, ins, *ip);
+ ins->type = STACK_MP;
+ ins->inst_left = *sp;
+ ins->klass = klass;
+ ins->inst_newa_class = klass;
+ }
ip += 5;
*sp++ = ins;
break;
+ }
case CEE_MKREFANY: {
- MonoInst *loc, *klassconst;
+ MonoInst *loc;
+ int context_used = 0;
CHECK_STACK (1);
- MONO_INST_NEW (cfg, ins, *ip);
--sp;
CHECK_OPSIZE (5);
- klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+ token = read32 (ip + 1);
+ klass = mono_class_get_full (image, token, generic_context);
CHECK_TYPELOAD (klass);
mono_class_init (klass);
- ins->cil_code = ip;
- if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
- GENERIC_SHARING_FAILURE (CEE_MKREFANY);
+ if (cfg->generic_sharing_context) {
+ context_used = mono_class_check_context_used (klass);
+ if (context_used && cfg->compile_aot)
+ GENERIC_SHARING_FAILURE (CEE_MKREFANY);
+ }
loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
- NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
+ if (context_used) {
+ MonoInst *rgctx, *klass_type, *klass_klass, *loc_load;
+
+ GET_RGCTX (rgctx);
+ klass_klass = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
+ token, MINI_TOKEN_SOURCE_CLASS, generic_context,
+ rgctx, MONO_RGCTX_INFO_KLASS, ip);
+ GET_RGCTX (rgctx);
+ klass_type = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
+ token, MINI_TOKEN_SOURCE_CLASS, generic_context,
+ rgctx, MONO_RGCTX_INFO_TYPE, ip);
+
+ NEW_TEMPLOADA (cfg, loc_load, loc->inst_c0);
+
+ MONO_INST_NEW (cfg, ins, OP_MKREFANY_REGS);
+ NEW_GROUP (cfg, ins->inst_left, klass_type, klass_klass);
+ NEW_GROUP (cfg, ins->inst_right, *sp, loc_load);
+ } else {
+ MonoInst *klassconst;
+
+ NEW_PCONST (cfg, klassconst, klass);
+
+ MONO_INST_NEW (cfg, ins, *ip);
+ NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
+ NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
+ }
- NEW_PCONST (cfg, klassconst, klass);
- NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
-
MONO_ADD_INS (bblock, ins);
NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
if (cfg->opt & MONO_OPT_SHARED) {
int temp;
MonoInst *res, *store, *addr, *vtvar, *iargs [3];
+ int method_context_used;
- GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
+ if (cfg->generic_sharing_context)
+ method_context_used = mono_method_check_context_used (method);
+ else
+ method_context_used = 0;
vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
NEW_IMAGECONST (cfg, iargs [0], image);
NEW_ICONST (cfg, iargs [1], n);
- NEW_PCONST (cfg, iargs [2], generic_context);
- temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
+ if (method_context_used) {
+ MonoInst *rgctx;
+
+ GET_RGCTX (rgctx);
+ iargs [2] = get_runtime_generic_context_method (cfg, method, bblock, method,
+ generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+ temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper_generic_shared,
+ iargs, ip);
+ } else {
+ NEW_PCONST (cfg, iargs [2], generic_context);
+ temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
+ }
NEW_TEMPLOAD (cfg, res, temp);
NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
if ((ip + 10 < end) && ip_in_bb (cfg, bblock, ip + 5) &&
handle_class == mono_defaults.typehandle_class &&
((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) &&
- (cmethod = mini_get_method (method, read32 (ip + 6), NULL, generic_context)) &&
+ (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
(cmethod->klass == mono_defaults.monotype_class->parent) &&
(strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
MonoClass *tclass = mono_class_from_mono_type (handle);
} else {
MonoInst *store, *addr, *vtvar;
- GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
+ if (context_used) {
+ MonoInst *rgctx;
- if (cfg->compile_aot)
+ g_assert (!cfg->compile_aot);
+
+ GET_RGCTX (rgctx);
+ if (handle_class == mono_defaults.typehandle_class) {
+ ins = get_runtime_generic_context_ptr (cfg, method,
+ bblock,
+ mono_class_from_mono_type (handle), token,
+ MINI_TOKEN_SOURCE_CLASS, generic_context,
+ rgctx, MONO_RGCTX_INFO_TYPE, ip);
+ } else if (handle_class == mono_defaults.methodhandle_class) {
+ ins = get_runtime_generic_context_method (cfg, method,
+ bblock, handle, generic_context,
+ rgctx, MONO_RGCTX_INFO_METHOD, ip);
+ } else if (handle_class == mono_defaults.fieldhandle_class) {
+ ins = get_runtime_generic_context_field (cfg, method,
+ bblock, handle, generic_context,
+ rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
+ } else {
+ g_assert_not_reached ();
+ }
+ }
+ else if (cfg->compile_aot) {
NEW_LDTOKENCONST (cfg, ins, image, n);
- else
+ } else {
NEW_PCONST (cfg, ins, handle);
+ }
vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
case CEE_ENDFINALLY:
MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
MONO_ADD_INS (bblock, ins);
- ins->cil_code = ip++;
+ ip++;
start_new_bblock = 1;
/*
*/
while (sp != stack_start) {
MONO_INST_NEW (cfg, ins, CEE_POP);
- ins->cil_code = ip;
sp--;
ins->inst_i0 = *sp;
MONO_ADD_INS (bblock, ins);
/* empty the stack */
while (sp != stack_start) {
MONO_INST_NEW (cfg, ins, CEE_POP);
- ins->cil_code = ip;
sp--;
ins->inst_i0 = *sp;
MONO_ADD_INS (bblock, ins);
MonoInst *load;
NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
- load->cil_code = ip;
temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_undeniable_exception, NULL, ip);
NEW_TEMPLOAD (cfg, *sp, temp);
MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
ins->inst_left = *sp;
ins->inst_right = load;
- ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
}
}
tblock = tmp->data;
link_bblock (cfg, bblock, tblock);
MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
- ins->cil_code = ip;
ins->inst_target_bb = tblock;
MONO_ADD_INS (bblock, ins);
}
}
MONO_INST_NEW (cfg, ins, OP_BR);
- ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
sp -= 2;
handle_loaded_temps (cfg, bblock, stack_start, sp);
MONO_ADD_INS (bblock, ins);
- ins->cil_code = ip++;
+ ip++;
ins->inst_i0 = sp [0];
ins->inst_i1 = sp [1];
inline_costs += 1;
if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
- ins->cil_code = ip;
*sp++ = ins;
ip += 6;
break;
}
}
NEW_PCONST (cfg, ins, ptr);
- ins->cil_code = ip;
*sp++ = ins;
ip += 6;
inline_costs += 10 * num_calls++;
CHECK_STACK (1);
--sp;
MONO_INST_NEW (cfg, ins, OP_VTADDR);
- ins->cil_code = ip;
ins->type = STACK_MP;
ins->inst_left = *sp;
*sp++ = ins;
CHECK_STACK (1);
--sp;
MONO_INST_NEW (cfg, ins, OP_OBJADDR);
- ins->cil_code = ip;
ins->type = STACK_MP;
ins->inst_left = *sp;
*sp++ = ins;
UNVERIFIED;
MONO_INST_NEW (cfg, ins, OP_BR);
- ins->cil_code = ip;
ins->inst_target_bb = end_bblock;
MONO_ADD_INS (bblock, ins);
link_bblock (cfg, bblock, end_bblock);
ins->type = STACK_I4;
ins->inst_left = *sp;
ins->inst_newa_class = klass;
- ins->cil_code = ip;
*sp++ = emit_tree (cfg, bblock, ins, ip + 6);
ip += 6;
break;
CHECK_OPSIZE (6);
token = read32 (ip + 2);
NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
- ins->cil_code = ip;
*sp++ = ins;
ip += 6;
inline_costs += 10 * num_calls++;
CHECK_OPSIZE (6);
MONO_INST_NEW (cfg, ins, OP_TLS_GET);
ins->inst_offset = (gint32)read32 (ip + 2);
- ins->cil_code = ip;
ins->type = STACK_PTR;
*sp++ = ins;
ip += 6;
vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL);
NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
- addr->cil_code = ip;
MONO_INST_NEW (cfg, ins, OP_ARGLIST);
- ins->cil_code = ip;
ins->inst_left = addr;
MONO_ADD_INS (bblock, ins);
NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
- ins->cil_code = ip;
*sp++ = ins;
ip += 2;
break;
sp -= 2;
cmp->inst_i0 = sp [0];
cmp->inst_i1 = sp [1];
- cmp->cil_code = ip;
type_from_op (cmp);
CHECK_TYPE (cmp);
- ins->cil_code = ip;
ins->type = STACK_I4;
ins->inst_i0 = cmp;
#if MONO_ARCH_SOFT_FLOAT
MonoInst *argconst;
MonoMethod *cil_method, *ctor_method;
int temp;
- gboolean is_shared;
+ gboolean is_shared = FALSE;
+ int context_used = 0;
CHECK_STACK_OVF (1);
CHECK_OPSIZE (6);
n = read32 (ip + 2);
- cmethod = mini_get_method (method, n, NULL, generic_context);
+ cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
if (!cmethod)
goto load_error;
mono_class_init (cmethod->klass);
- if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
- GENERIC_SHARING_FAILURE (CEE_LDFTN);
+ if (cfg->generic_sharing_context)
+ context_used = mono_method_check_context_used (cmethod);
- is_shared = (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
- (cmethod->klass->generic_class || cmethod->klass->generic_container) &&
- mono_class_generic_sharing_enabled (cmethod->klass);
+ if (mono_class_generic_sharing_enabled (cmethod->klass)) {
+ if ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
+ (cmethod->klass->generic_class ||
+ cmethod->klass->generic_container)) {
+ is_shared = TRUE;
+ }
+ if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst)
+ is_shared = TRUE;
+ }
cil_method = cmethod;
if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
#if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
/* FIXME: SGEN support */
/* FIXME: handle shared static generic methods */
- if (!is_shared && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
+ /* FIXME: handle this in shared code */
+ if (!is_shared && !context_used && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
MonoInst *target_ins;
ip += 6;
handle_loaded_temps (cfg, bblock, stack_start, sp);
- if (is_shared)
+ if (context_used) {
+ MonoInst *rgctx;
+
+ if (is_shared)
+ cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
+
+ GET_RGCTX (rgctx);
+ argconst = get_runtime_generic_context_method (cfg, method,
+ bblock, cmethod,
+ generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+ } else if (is_shared) {
NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
- else
+ } else {
NEW_METHODCONST (cfg, argconst, cmethod);
+ }
if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
else
case CEE_LDVIRTFTN: {
MonoInst *args [2];
int temp;
+ int context_used = 0;
CHECK_STACK (1);
CHECK_OPSIZE (6);
n = read32 (ip + 2);
- cmethod = mini_get_method (method, n, NULL, generic_context);
+ cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
if (!cmethod)
goto load_error;
mono_class_init (cmethod->klass);
- if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
- GENERIC_SHARING_FAILURE (CEE_LDVIRTFTN);
+ if (cfg->generic_sharing_context)
+ context_used = mono_method_check_context_used (cmethod);
if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
if (check_linkdemand (cfg, method, cmethod, bblock, ip))
--sp;
args [0] = *sp;
- NEW_METHODCONST (cfg, args [1], cmethod);
+ if (context_used) {
+ MonoInst *rgctx;
+
+ GET_RGCTX (rgctx);
+ args [1] = get_runtime_generic_context_method (cfg, method,
+ bblock, cmethod,
+ generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+ } else {
+ NEW_METHODCONST (cfg, args [1], cmethod);
+ }
temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
NEW_TEMPLOAD (cfg, *sp, temp);
sp ++;
CHECK_ARG (n);
NEW_ARGLOAD (cfg, ins, n);
LDARG_SOFT_FLOAT (cfg, ins, n, ip);
- ins->cil_code = ip;
*sp++ = ins;
ip += 4;
break;
n = read16 (ip + 2);
CHECK_ARG (n);
NEW_ARGLOADA (cfg, ins, n);
- ins->cil_code = ip;
*sp++ = ins;
ip += 4;
break;
n = read16 (ip + 2);
CHECK_ARG (n);
NEW_ARGSTORE (cfg, ins, n, *sp);
- ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
UNVERIFIED;
STARG_SOFT_FLOAT (cfg, ins, n, ip);
CHECK_LOCAL (n);
NEW_LOCLOAD (cfg, ins, n);
LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
- ins->cil_code = ip;
*sp++ = ins;
ip += 4;
break;
n = read16 (ip + 2);
CHECK_LOCAL (n);
NEW_LOCLOADA (cfg, ins, n);
- ins->cil_code = ip;
*sp++ = ins;
ip += 4;
break;
NEW_LOCSTORE (cfg, ins, n, *sp);
if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
UNVERIFIED;
- ins->cil_code = ip;
STLOC_SOFT_FLOAT (cfg, ins, n, ip);
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, n);
goto inline_failure;
MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
ins->inst_left = *sp;
- ins->cil_code = ip;
ins->type = STACK_PTR;
cfg->flags |= MONO_CFG_HAS_ALLOCA;
UNVERIFIED;
MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
ins->inst_left = *sp;
- ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
start_new_bblock = 1;
ip += 2;
inline_costs += 100000;
ip += 2;
break;
- case CEE_INITOBJ: {
- gboolean generic_shared = FALSE;
-
+ case CEE_INITOBJ:
CHECK_STACK (1);
--sp;
CHECK_OPSIZE (6);
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
- if (cfg->generic_sharing_context && mono_class_check_context_used (klass)) {
- if (generic_class_is_reference_type (cfg, klass))
- generic_shared = TRUE;
- else
- GENERIC_SHARING_FAILURE (CEE_INITOBJ);
- }
-
- if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || generic_shared) {
+ if (generic_class_is_reference_type (cfg, klass)) {
MonoInst *store, *load;
NEW_PCONST (cfg, load, NULL);
- load->cil_code = ip;
load->type = STACK_OBJ;
load->klass = klass;
MONO_INST_NEW (cfg, store, CEE_STIND_REF);
- store->cil_code = ip;
handle_loaded_temps (cfg, bblock, stack_start, sp);
MONO_ADD_INS (bblock, store);
store->inst_i0 = sp [0];
store->inst_i1 = load;
} else {
+ GENERIC_SHARING_FAILURE (CEE_INITOBJ);
handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
}
ip += 6;
inline_costs += 1;
break;
- }
case CEE_CONSTRAINED_:
/* FIXME: implement */
CHECK_OPSIZE (6);
g_assert (handler_offset != -1);
NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
- load->cil_code = ip;
MONO_INST_NEW (cfg, ins, OP_RETHROW);
ins->inst_left = load;
- ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
sp = stack_start;
link_bblock (cfg, bblock, end_bblock);
token = mono_class_value_size (klass, &align);
}
NEW_ICONST (cfg, ins, token);
- ins->cil_code = ip;
*sp++= ins;
ip += 6;
break;
ins->inst_left = *sp;
ins->type = STACK_VTYPE;
ins->klass = mono_defaults.typehandle_class;
- ins->cil_code = ip;
ip += 2;
*sp++ = ins;
break;
if (header->init_locals) {
MonoInst *store;
+ cfg->ip = header->code;
for (i = 0; i < header->num_locals; ++i) {
MonoType *ptype = header->locals [i];
int t = ptype->type;
}
}
+ cfg->ip = NULL;
+
/* resolve backward branches in the middle of an existing basic block */
for (tmp = bb_recheck; tmp; tmp = tmp->next) {
bblock = tmp->data;
* STACK_ALIGN is set to the alignment needed by the locals area.
*/
gint32*
-mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stack_size, guint32 *stack_align)
+mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
{
int i, slot, offset, size;
guint32 align;
MonoType *t;
int nvtypes;
- scalar_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
+ scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
vtype_stack_slots = NULL;
nvtypes = 0;
- offsets = mono_mempool_alloc (m->mempool, sizeof (gint32) * m->num_varinfo);
- for (i = 0; i < m->num_varinfo; ++i)
+ offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
+ for (i = 0; i < cfg->num_varinfo; ++i)
offsets [i] = -1;
- for (i = m->locals_start; i < m->num_varinfo; i++) {
- inst = m->varinfo [i];
- vmv = MONO_VARINFO (m, i);
+ for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
+ inst = cfg->varinfo [i];
+ vmv = MONO_VARINFO (cfg, i);
if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
continue;
vars = g_list_prepend (vars, vmv);
}
- vars = mono_varlist_sort (m, vars, 0);
+ vars = mono_varlist_sort (cfg, vars, 0);
offset = 0;
*stack_align = 0;
for (l = vars; l; l = l->next) {
vmv = l->data;
- inst = m->varinfo [vmv->idx];
+ inst = cfg->varinfo [vmv->idx];
/* inst->backend.is_pinvoke indicates native sized value types, this is used by the
* pinvoke wrappers when they call functions returning structures */
/* Fall through */
case MONO_TYPE_VALUETYPE:
if (!vtype_stack_slots)
- vtype_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * 256);
+ vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
for (i = 0; i < nvtypes; ++i)
if (t->data.klass == vtype_stack_slots [i].vtype)
break;
}
slot = 0xffffff;
- if (m->comp_done & MONO_COMP_LIVENESS) {
+ if (cfg->comp_done & MONO_COMP_LIVENESS) {
//printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
/* expire old intervals in active */
//printf ("EXPIR %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
- slot_info->slots = g_slist_prepend_mempool (m->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
+ slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
}
/*
slot_info->slots = slot_info->slots->next;
}
- slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
+ slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
}
}
/*
if (count == atoi (getenv ("COUNT")))
- printf ("LAST: %s\n", mono_method_full_name (m->method, TRUE));
+ printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
if (count > atoi (getenv ("COUNT")))
slot = 0xffffff;
else {
}
*/
}
+
+ if (cfg->disable_reuse_stack_slots)
+ slot = 0xffffff;
+
if (slot == 0xffffff) {
/*
* Allways allocate valuetypes to sizeof (gpointer) to allow more
else {
MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
+ g_assert (vtable);
NEW_VTABLECONST (cfg, iargs [0], vtable);
iargs [1] = tree->inst_newa_len;
void
mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
{
- MONO_INST_LIST_ADD_TAIL (&inst->node, &bb->ins_list);
+ MONO_ADD_INS (bb, inst);
}
void
return mono_jit_tls_id;
}
+gint32
+mono_get_jit_tls_offset (void)
+{
+#ifdef HAVE_KW_THREAD
+ int offset;
+ MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset);
+ return offset;
+#else
+ return -1;
+#endif
+}
+
gint32
mono_get_lmf_tls_offset (void)
{
TlsSetValue (mono_jit_tls_id, jit_tls);
+#ifdef HAVE_KW_THREAD
+ mono_jit_tls = jit_tls;
+#endif
+
jit_tls->abort_func = abort_func;
jit_tls->end_of_stack = stack_start;
}
}
+static MonoInst*
+mono_create_tls_get (MonoCompile *cfg, int offset)
+{
+#ifdef MONO_ARCH_HAVE_TLS_GET
+ MonoInst* ins;
+
+ if (offset == -1)
+ return NULL;
+
+ MONO_INST_NEW (cfg, ins, OP_TLS_GET);
+ ins->dreg = mono_regstate_next_int (cfg->rs);
+ ins->inst_offset = offset;
+ return ins;
+#else
+ return NULL;
+#endif
+}
+
+MonoInst*
+mono_get_jit_tls_intrinsic (MonoCompile *cfg)
+{
+ return mono_create_tls_get (cfg, mono_get_jit_tls_offset ());
+}
+
void
mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
{
target = code;
} else {
/* get the trampoline to the method from the domain */
- if (method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE)
+ if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE)
target = mono_ldftn_nosync (patch_info->data.method);
else
target = mono_create_jit_trampoline (patch_info->data.method);
break;
case MONO_PATCH_INFO_VTABLE:
target = mono_class_vtable (domain, patch_info->data.klass);
+ g_assert (target);
break;
- case MONO_PATCH_INFO_CLASS_INIT:
- target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
+ case MONO_PATCH_INFO_CLASS_INIT: {
+ MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.klass);
+
+ g_assert (vtable);
+ target = mono_create_class_init_trampoline (vtable);
break;
+ }
case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
target = mono_create_delegate_trampoline (patch_info->data.klass);
break;
case MONO_PATCH_INFO_SFLDA: {
MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
+
+ g_assert (vtable);
if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
/* Done by the generated code */
;
int i;
if (cfg->verbose_level > 1) {
- printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
+ printf ("remove_block_if_useless, removed BB%d\n", bb->block_num);
}
/* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
if (nts [1]) {
emit_state (cfg, kids [1], nts [1]);
if (nts [2]) {
- g_assert (!nts [3]);
emit_state (cfg, kids [2], nts [2]);
+ if (nts [3]) {
+ g_assert (!nts [4]);
+ emit_state (cfg, kids [3], nts [3]);
+ }
}
}
}
}
#endif
+ cfg->ip = tree->cil_code;
if (!(mbstate = mono_burg_label (tree, cfg))) {
g_warning ("unable to label tree %p", tree);
mono_print_tree (tree);
mono_mempool_empty (cfg->state_pool);
}
mono_mempool_destroy (cfg->state_pool);
+
+ cfg->ip = NULL;
}
/*
mono_jit_stats.methods_compiled++;
if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
mono_profiler_method_jit (method);
+ if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
+ MONO_PROBE_METHOD_COMPILE_BEGIN (method);
if (compile_aot)
/* We are passed the original generic method definition */
try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
- (opts & MONO_OPT_GSHARED) && (method->generic_container || method->klass->generic_container);
+ (opts & MONO_OPT_GSHARED) && (method->is_generic || method->klass->generic_container);
else
try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
(opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method);
g_assert (method->klass->generic_class->container_class == declaring_method->klass);
}
- if (declaring_method->generic_container)
- shared_context = &declaring_method->generic_container->context;
+ if (declaring_method->is_generic)
+ shared_context = &(mono_method_get_generic_container (declaring_method)->context);
else
shared_context = &declaring_method->klass->generic_container->context;
cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
cfg->token_info_hash = g_hash_table_new (NULL, NULL);
+ /* The debugger has no liveness information, so avoid sharing registers/stack slots */
+ if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
+ cfg->disable_reuse_registers = TRUE;
+ cfg->disable_reuse_stack_slots = TRUE;
+ /*
+ * This decreases the change the debugger will read registers/stack slots which are
+ * not yet initialized.
+ */
+ cfg->disable_initlocals_opt = TRUE;
+
+ /* Temporarily disable this when running in the debugger until we have support
+ * for this in the debugger. */
+ cfg->disable_omit_fp = TRUE;
+
+ // cfg->opt |= MONO_OPT_SHARED;
+ cfg->opt &= ~MONO_OPT_INLINE;
+ cfg->opt &= ~MONO_OPT_COPYPROP;
+ cfg->opt &= ~MONO_OPT_CONSPROP;
+ }
+
header = mono_method_get_header (method_to_compile);
if (!header) {
cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
+ if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+ MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
return cfg;
ip = (guint8 *)header->code;
- if (cfg->verbose_level > 2)
- g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
+ if (cfg->verbose_level > 2) {
+ if (cfg->generic_sharing_context)
+ g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE));
+ else
+ g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
+ }
/*
* create MonoInst* which represents arguments and local variables
if ((i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
- if (compile_aot)
+ if (compile_aot) {
+ if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+ MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
return cfg;
+ }
mono_destroy_compile (cfg);
try_generic_shared = FALSE;
goto restart_compile;
}
g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
+ if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+ MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
/* cfg contains the details of the failure, so let the caller cleanup */
}
/* after method_to_ir */
- if (parts == 1)
+ if (parts == 1) {
+ if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+ MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
return cfg;
+ }
//#define DEBUGSSA "logic_run"
#define DEBUGSSA_CLASS "Tests"
#endif
/* after SSA translation */
- if (parts == 2)
+ if (parts == 2) {
+ if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+ MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
return cfg;
+ }
if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
if (cfg->comp_done & MONO_COMP_SSA) {
#endif
/* after SSA removal */
- if (parts == 3)
+ if (parts == 3) {
+ if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+ MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
return cfg;
+ }
if (cfg->verbose_level > 4) {
printf ("BEFORE DECOMPSE START\n");
inst = cfg->rgctx_var;
g_assert (inst->opcode == OP_REGOFFSET);
} else {
- inst = cfg->varinfo [0];
+ inst = cfg->args [0];
}
if (inst->opcode == OP_REGVAR) {
}
mono_jit_stats.native_code_size += cfg->code_len;
+ if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+ MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
MonoCompile *cfg;
gpointer code = NULL;
MonoJitInfo *info;
+ MonoVTable *vtable;
#ifdef MONO_USE_AOT_COMPILER
if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
mono_domain_lock (domain);
if ((code = mono_aot_get_method (domain, method))) {
mono_domain_unlock (domain);
- mono_runtime_class_init (mono_class_vtable (domain, method->klass));
+ vtable = mono_class_vtable (domain, method->klass);
+ g_assert (vtable);
+ mono_runtime_class_init (vtable);
return code;
}
MonoMethod *nm;
MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
- if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
- g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
-
if (!piinfo->addr) {
if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
piinfo->addr = mono_lookup_internal_call (method);
+ else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
+#ifdef PLATFORM_WIN32
+ g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono in modules loaded from byte arrays. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
+#else
+ g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono on this platform. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
+#endif
else
- if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
- mono_lookup_pinvoke_call (method, NULL, NULL);
+ mono_lookup_pinvoke_call (method, NULL, NULL);
}
nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc);
return mono_get_addr_from_ftnptr (mono_compile_method (nm));
mono_domain_unlock (target_domain);
- mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
+ vtable = mono_class_vtable (target_domain, method->klass);
+ if (!vtable) {
+ MonoException *exc;
+ exc = mono_class_get_exception_for_failure (method->klass);
+ g_assert (exc);
+ mono_raise_exception (exc);
+ }
+ mono_runtime_class_init (vtable);
return code;
}
if ((info = lookup_method (target_domain, method))) {
/* We can't use a domain specific method in another domain */
if (! ((domain != target_domain) && !info->domain_neutral)) {
+ MonoVTable *vtable;
+
mono_domain_unlock (target_domain);
mono_jit_stats.methods_lookups++;
- mono_runtime_class_init (mono_class_vtable (domain, method->klass));
+ vtable = mono_class_vtable (domain, method->klass);
+ mono_runtime_class_init (vtable);
return mono_create_ftnptr (target_domain, info->code_start);
}
}
if (destroy)
mono_code_manager_destroy (ji->code_mp);
- mono_thread_hazardous_free_or_queue (ji->ji, g_free);
g_free (ji);
}
MonoMethod *invoke;
MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
void* compiled_method;
+ MonoVTable *vtable;
if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
/* We need this here becuase mono_marshal_get_runtime_invoke can be place
* the helper method in System.Object and not the target class
*/
- mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
+ vtable = mono_class_vtable (mono_domain_get (), method->klass);
+ g_assert (vtable);
+ mono_runtime_class_init (vtable);
if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
(method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
mono_arch_handle_exception (ctx, exc, FALSE);
}
+#if defined(__i386__) || defined(__x86_64__)
+#define FULL_STAT_PROFILER_BACKTRACE 1
+#define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
+#define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
+#if MONO_ARCH_STACK_GROWS_UP
+#define IS_BEFORE_ON_STACK <
+#define IS_AFTER_ON_STACK >
+#else
+#define IS_BEFORE_ON_STACK >
+#define IS_AFTER_ON_STACK <
+#endif
+#else
+#define FULL_STAT_PROFILER_BACKTRACE 0
+#endif
+
+#if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
+
+static void
+SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
+{
+ NOT_IMPLEMENTED;
+}
+
+#else
+
static void
SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
{
+ int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
GET_CONTEXT;
+
+ if (call_chain_depth == 0) {
+ mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
+ } else {
+ MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+ int current_frame_index = 1;
+ MonoContext mono_context;
+#if FULL_STAT_PROFILER_BACKTRACE
+ guchar *current_frame;
+ guchar *stack_bottom;
+ guchar *stack_top;
+#else
+ MonoDomain *domain;
+#endif
+ guchar *ips [call_chain_depth + 1];
- mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
+ mono_arch_sigctx_to_monoctx (ctx, &mono_context);
+ ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
+
+ if (jit_tls != NULL) {
+#if FULL_STAT_PROFILER_BACKTRACE
+ stack_bottom = jit_tls->end_of_stack;
+ stack_top = MONO_CONTEXT_GET_SP (&mono_context);
+ current_frame = MONO_CONTEXT_GET_BP (&mono_context);
+
+ while ((current_frame_index <= call_chain_depth) &&
+ (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
+ ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
+ ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
+ current_frame_index ++;
+ stack_top = current_frame;
+ current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
+ }
+#else
+ domain = mono_domain_get ();
+ if (domain != NULL) {
+ MonoLMF *lmf = NULL;
+ MonoJitInfo *ji;
+ MonoJitInfo res;
+ MonoContext new_mono_context;
+ int native_offset;
+ ji = mono_arch_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
+ &new_mono_context, NULL, &lmf, &native_offset, NULL);
+ while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
+ ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
+ current_frame_index ++;
+ mono_context = new_mono_context;
+ ji = mono_arch_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
+ &new_mono_context, NULL, &lmf, &native_offset, NULL);
+ }
+ }
+#endif
+ }
+
+
+ mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
+ }
}
+#endif
+
static void
SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
{
debug_options.collect_pagefault_stats = TRUE;
else if (!strcmp (arg, "break-on-unverified"))
debug_options.break_on_unverified = TRUE;
+ else if (!strcmp (arg, "no-gdb-backtrace"))
+ debug_options.no_gdb_backtrace = TRUE;
else {
fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
- fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
+ fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace'\n");
exit (1);
}
}
}
+MonoDebugOptions *
+mini_get_debug_options (void)
+{
+ return &debug_options;
+}
+
MonoDomain *
mini_init (const char *filename, const char *runtime_version)
{
MonoDomain *domain;
+ MONO_PROBE_VES_INIT_BEGIN ();
+
#ifdef __linux__
if (access ("/proc/self/maps", F_OK) != 0) {
g_print ("Mono requires /proc to be mounted.\n");
mono_install_handler (mono_arch_get_throw_exception ());
#endif
mono_install_stack_walk (mono_jit_walk_stack);
- mono_install_init_vtable (mono_aot_init_vtable);
mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
mono_install_get_class_from_name (mono_aot_get_class_from_name);
mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
register_icall (mono_class_static_field_address , "mono_class_static_field_address",
"ptr ptr ptr", FALSE);
register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
+ register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
+ "ptr ptr ptr ptr", FALSE);
register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
+ register_icall (mono_helper_compile_generic_method_wo_context, "compile_generic_method_wo_context",
+ "ptr object ptr ptr", FALSE);
register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
- register_icall (mono_helper_get_rgctx_other_ptr, "get_rgctx_other_ptr", "ptr ptr ptr int32 int32 int32 int32", FALSE);
+ register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
register_icall (mono_break, "mono_break", NULL, TRUE);
register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
mono_generic_sharing_init ();
mono_thread_attach (domain);
+
+ MONO_PROBE_VES_INIT_END ();
+
return domain;
}