#include <config.h>
#include <signal.h>
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <math.h>
+#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
#ifdef PLATFORM_MACOSX
#include <mach/mach.h>
#include <pthread.h>
#endif
+#ifdef PLATFORM_WIN32
+#define _WIN32_WINNT 0x0500
+#endif
+
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
#include <mono/metadata/assembly.h>
#include <mono/metadata/loader.h>
-#include <mono/metadata/cil-coff.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/class.h>
#include <mono/metadata/object.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/monitor.h>
+#include <mono/metadata/gc-internal.h>
#include <mono/metadata/security-manager.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/rawbuffer.h>
+#include <mono/metadata/security-core-clr.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/os/gc_wrapper.h>
#include "mini.h"
#include "aliasing.h"
+#include "debug-mini.h"
+
#define BRANCH_COST 100
#define INLINE_LENGTH_LIMIT 20
#define INLINE_FAILURE do {\
if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
goto inline_failure;\
} while (0)
+#define CHECK_CFG_EXCEPTION do {\
+ if (cfg->exception_type != MONO_EXCEPTION_NONE)\
+ goto exception_exit;\
+ } while (0)
+#define METHOD_ACCESS_FAILURE do { \
+ char *method_fname = mono_method_full_name (method, TRUE); \
+ char *cil_method_fname = mono_method_full_name (cil_method, TRUE); \
+ cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS; \
+ cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname); \
+ g_free (method_fname); \
+ g_free (cil_method_fname); \
+ goto exception_exit; \
+ } while (0)
+#define FIELD_ACCESS_FAILURE do { \
+ char *method_fname = mono_method_full_name (method, TRUE); \
+ char *field_fname = mono_field_full_name (field); \
+ cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS; \
+ cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname); \
+ g_free (method_fname); \
+ g_free (field_fname); \
+ goto exception_exit; \
+ } while (0)
+#define GENERIC_SHARING_FAILURE do { \
+ if (cfg->generic_sharing_context) { \
+ /* g_print ("sharing failed for method %s.%s in %s:%d\n", method->klass->name, method->name, __FILE__, __LINE__); */ \
+ cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; \
+ goto exception_exit; \
+ } \
+ } while (0)
/*
* this is used to determine when some branch optimizations are possible: we exclude FP compares
#define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
#define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
-#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == CEE_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
+#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == OP_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
#define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
- guint inline_offset, gboolean is_virtual_call);
+ guint inline_offset, gboolean is_virtual_call, MonoGenericContext *shared_context);
/* helper methods signature */
static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
#ifndef DISABLE_AOT
gboolean mono_compile_aot = FALSE;
#endif
-gboolean mono_use_security_manager = FALSE;
+MonoMethodDesc *mono_inject_async_exc_method = NULL;
+int mono_inject_async_exc_pos;
static int mini_verbose = 0;
static MonoDebugOptions debug_options;
+#ifdef VALGRIND_JIT_REGISTER_MAP
+static int valgrind_register = 0;
+#endif
+
/*
* Address of the trampoline code. This is used by the debugger to check
* whether a method is a trampoline.
mono_running_on_valgrind (void)
{
#ifdef HAVE_VALGRIND_MEMCHECK_H
- if (RUNNING_ON_VALGRIND)
+ if (RUNNING_ON_VALGRIND){
+#ifdef VALGRIND_JIT_REGISTER_MAP
+ valgrind_register = TRUE;
+#endif
return TRUE;
- else
+ } else
return FALSE;
#else
return FALSE;
* block_num: unique ID assigned at bblock creation
*/
#define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
-#define ADD_BBLOCK(cfg,bbhash,b) do { \
- g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
+#define ADD_BBLOCK(cfg,b) do { \
+ cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b); \
(b)->block_num = cfg->num_bblocks++; \
(b)->real_offset = real_offset; \
} while (0)
-#define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
- (tblock) = g_hash_table_lookup (bbhash, (ip)); \
+#define GET_BBLOCK(cfg,tblock,ip) do { \
+ (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
if (!(tblock)) { \
if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
(tblock) = NEW_BBLOCK (cfg); \
(tblock)->cil_code = (ip); \
- ADD_BBLOCK (cfg, (bbhash), (tblock)); \
+ ADD_BBLOCK (cfg, (tblock)); \
} \
} while (0)
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->ssa_op = MONO_SSA_LOAD; \
(dest)->inst_i0 = arg_array [(num)]; \
- (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
- type_to_eval_stack_type (param_types [(num)], (dest)); \
+ (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
+ type_to_eval_stack_type ((cfg), param_types [(num)], (dest)); \
(dest)->klass = (dest)->inst_i0->klass; \
}} while (0)
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->ssa_op = MONO_SSA_LOAD; \
(dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
- (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
- type_to_eval_stack_type (header->locals [(num)], (dest)); \
+ (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
+ type_to_eval_stack_type ((cfg), header->locals [(num)], (dest)); \
(dest)->klass = (dest)->inst_i0->klass; \
} while (0)
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->ssa_op = MONO_SSA_LOAD; \
(dest)->inst_i0 = (cfg)->varinfo [(num)]; \
- (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
- type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest)); \
+ (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
+ type_to_eval_stack_type ((cfg), (dest)->inst_i0->inst_vtype, (dest)); \
(dest)->klass = (dest)->inst_i0->klass; \
} while (0)
#define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->inst_left = addr; \
- (dest)->opcode = mono_type_to_ldind (vtype); \
- type_to_eval_stack_type (vtype, (dest)); \
+ (dest)->opcode = mini_type_to_ldind ((cfg), vtype); \
+ type_to_eval_stack_type ((cfg), vtype, (dest)); \
/* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
} while (0)
#define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->inst_i0 = addr; \
- (dest)->opcode = mono_type_to_stind (vtype); \
+ (dest)->opcode = mini_type_to_stind ((cfg), vtype); \
(dest)->inst_i1 = (value); \
/* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
} while (0)
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->ssa_op = MONO_SSA_STORE; \
(dest)->inst_i0 = (cfg)->varinfo [(num)]; \
- (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype); \
+ (dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
(dest)->inst_i1 = (inst); \
(dest)->klass = (dest)->inst_i0->klass; \
} while (0)
#define NEW_LOCSTORE(cfg,dest,num,inst) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = mono_type_to_stind (header->locals [(num)]); \
+ (dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
(dest)->ssa_op = MONO_SSA_STORE; \
(dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
(dest)->inst_i1 = (inst); \
#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)); \
- (dest)->opcode = mono_type_to_stind (param_types [(num)]); \
+ (dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
(dest)->ssa_op = MONO_SSA_STORE; \
(dest)->inst_i0 = arg_array [(num)]; \
(dest)->inst_i1 = (inst); \
(dest)->klass = (dest)->inst_i0->klass; \
} while (0)
+#define NEW_MEMCPY(cfg,dest,dst,src,memcpy_size,memcpy_align) do { \
+ 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); \
+ } while (0)
+
+#define NEW_MEMSET(cfg,dest,dst,imm,memcpy_size,memcpy_align) do { \
+ 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; \
ins->inst_i0 = cmp; \
MONO_ADD_INS (bblock, ins); \
ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
- GET_BBLOCK (cfg, bbhash, tblock, target); \
+ GET_BBLOCK (cfg, tblock, target); \
link_bblock (cfg, bblock, tblock); \
ins->inst_true_bb = tblock; \
CHECK_BBLOCK (target, ip, tblock); \
ins->inst_false_bb = (next_block); \
start_new_bblock = 1; \
} else { \
- GET_BBLOCK (cfg, bbhash, tblock, ip); \
+ GET_BBLOCK (cfg, tblock, ip); \
link_bblock (cfg, bblock, tblock); \
ins->inst_false_bb = tblock; \
start_new_bblock = 2; \
ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
MONO_ADD_INS (bblock, ins); \
ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
- GET_BBLOCK (cfg, bbhash, tblock, target); \
+ GET_BBLOCK (cfg, tblock, target); \
link_bblock (cfg, bblock, tblock); \
ins->inst_true_bb = tblock; \
CHECK_BBLOCK (target, ip, tblock); \
- GET_BBLOCK (cfg, bbhash, tblock, ip); \
+ GET_BBLOCK (cfg, tblock, ip); \
link_bblock (cfg, bblock, tblock); \
ins->inst_false_bb = tblock; \
start_new_bblock = 2; \
if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
(!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
if (clause->flags == type) {
- handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
+ handler = cfg->cil_offset_to_bb [clause->handler_offset];
g_assert (handler);
res = g_list_append (res, handler);
}
}
}
-typedef struct {
- const guchar *code;
- MonoBasicBlock *best;
-} PrevStruct;
-
-static void
-previous_foreach (gconstpointer key, gpointer val, gpointer data)
+static MonoBasicBlock*
+find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
{
- PrevStruct *p = data;
- MonoBasicBlock *bb = val;
- //printf ("FIDPREV %d %p %p %p %p %p %d %d %d\n", bb->block_num, p->code, bb, p->best, bb->cil_code, p->best->cil_code,
- //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
-
- if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
- p->best = bb;
-}
+ MonoBasicBlock *best = start;
+ int i;
-static MonoBasicBlock*
-find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
- PrevStruct p;
+ for (i = 0; i < n_bblocks; ++i) {
+ if (bblocks [i]) {
+ MonoBasicBlock *bb = bblocks [i];
- p.code = code;
- p.best = start;
+ if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
+ best = bb;
+ }
+ }
- g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
- return p.best;
+ return best;
}
static void
* FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
*/
static void
-type_to_eval_stack_type (MonoType *type, MonoInst *inst)
+type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
{
MonoClass *klass;
case MONO_TYPE_GENERICINST:
type = &type->data.generic_class->container_class->byval_arg;
goto handle_enum;
+ case MONO_TYPE_VAR :
+ case MONO_TYPE_MVAR :
+ /* FIXME: all the arguments must be references for now,
+ * later look inside cfg and see if the arg num is
+ * really a reference
+ */
+ g_assert (cfg->generic_sharing_context);
+ inst->type = STACK_OBJ;
+ return;
default:
g_error ("unknown type 0x%02x in eval stack type", type->type);
}
ins->type = STACK_PTR;
switch (ins->inst_i0->type) {
case STACK_I4:
+ break;
case STACK_PTR:
case STACK_MP:
+#if SIZEOF_VOID_P == 8
+ ins->opcode = OP_LCONV_TO_U;
+#endif
break;
case STACK_I8:
ins->opcode = OP_LCONV_TO_U;
ins->type = STACK_R8;
ins->opcode += unops_op_map [ins->inst_i0->type];
return;
- case CEE_CKFINITE:
+ case OP_CKFINITE:
ins->type = STACK_R8;
return;
case CEE_CONV_U2:
}
#endif
+static guint
+mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
+{
+ if (cfg->generic_sharing_context && !type->byref) {
+ /* FIXME: all the arguments must be references for now,
+ * later look inside cfg and see if the arg num is
+ * really a reference
+ */
+ if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
+ return CEE_LDIND_REF;
+ }
+ return mono_type_to_ldind (type);
+}
+
+static guint
+mini_type_to_stind (MonoCompile* cfg, MonoType *type)
+{
+ if (cfg->generic_sharing_context && !type->byref) {
+ /* FIXME: all the arguments must be references for now,
+ * later look inside cfg and see if the arg num is
+ * really a reference
+ */
+ if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
+ return CEE_STIND_REF;
+ }
+ return mono_type_to_stind (type);
+}
+
/*
* When we need a pointer to the current domain many times in a method, we
* call mono_domain_get() once and we store the result in a local variable.
MONO_INIT_VARINFO (cfg->vars [num], num);
cfg->num_varinfo++;
- //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
+ if (cfg->verbose_level > 2)
+ g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
return inst;
}
memset (dest, 0, sizeof (MonoInst));
dest->ssa_op = MONO_SSA_LOAD;
dest->inst_i0 = cfg->varinfo [var_index];
- dest->opcode = mono_type_to_ldind (dest->inst_i0->inst_vtype);
- type_to_eval_stack_type (dest->inst_i0->inst_vtype, dest);
+ dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
+ type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
dest->klass = dest->inst_i0->klass;
}
return &ins->klass->this_arg;
else
return &mono_defaults.object_class->this_arg;
- case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
+ case STACK_OBJ:
+ /* ins->klass may not be set for ldnull.
+ * Also, if we have a boxed valuetype, we want an object lass,
+ * not the valuetype class
+ */
+ if (ins->klass && !ins->klass->valuetype)
+ return &ins->klass->byval_arg;
+ return &mono_defaults.object_class->byval_arg;
case STACK_VTYPE: return &ins->klass->byval_arg;
default:
g_error ("stack type %d to montype not handled\n", ins->type);
}
static MonoClass*
-array_access_to_klass (int opcode)
+array_access_to_klass (int opcode, MonoInst *array_obj)
{
switch (opcode) {
case CEE_LDELEM_U1:
case CEE_STELEM_R8:
return mono_defaults.double_class;
case CEE_LDELEM_REF:
- case CEE_STELEM_REF:
+ case CEE_STELEM_REF: {
+ MonoClass *klass = array_obj->klass;
+ /* FIXME: add assert */
+ if (klass && klass->rank)
+ return klass->element_class;
return mono_defaults.object_class;
+ }
default:
g_assert_not_reached ();
}
case CEE_BGT_UN:
case CEE_BLE_UN:
case CEE_BLT_UN:
- case CEE_BR:
+ case OP_BR:
case CEE_SWITCH:
prev = bb->code;
while (prev->next && prev->next != bb->last_ins)
NEW_TEMPLOAD (cfg, load, src);
NEW_TEMPSTORE (cfg, inst, dest, load);
+ /* FIXME: handle CEE_STIND_R4 */
if (inst->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, inst, dest);
handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
}
}
-/*
- * We try to share variables when possible
- */
-static MonoInst *
-mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
-{
- MonoInst *res;
- int pos, vnum;
-
- /* inlining can result in deeper stacks */
- if (slot >= mono_method_get_header (cfg->method)->max_stack)
- return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
-
- pos = ins->type - 1 + slot * STACK_MAX;
-
- switch (ins->type) {
- case STACK_I4:
- case STACK_I8:
- case STACK_R8:
- case STACK_PTR:
- case STACK_MP:
- case STACK_OBJ:
- if ((vnum = cfg->intvars [pos]))
- return cfg->varinfo [vnum];
- res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
- cfg->intvars [pos] = res->inst_c0;
- break;
- default:
- res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
- }
- return res;
-}
-
/*
* merge_stacks:
*
* in the inlined methods do not inherit their in_stack from
* the bblock they are inlined to. See bug #58863 for an
* example.
+ * This hack is disabled since it also prevents proper tracking of types.
*/
+#if 1
+ bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
+#else
if (cfg->inlined_method)
bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
else
bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
+#endif
}
}
}
for (i = 0; i < count; ++i) {
/* add store ops at the end of the bb, before the branch */
NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
+ /* FIXME: handle CEE_STIND_R4 */
if (inst->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
cfg->patch_info = ji;
}
+static void
+mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
+{
+ if (cfg->compile_aot) {
+ MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
+ jump_info_token->image = image;
+ jump_info_token->token = token;
+ g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
+ }
+}
+
/*
* When we add a tree of instructions, we need to ensure the instructions currently
* on the stack are executed before (like, if we load a value from a local).
temp->flags |= MONO_INST_IS_TEMP;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
store->cil_code = ins->cil_code;
+ /* FIXME: handle CEE_STIND_R4 */
if (store->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, store, temp->inst_c0);
handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
if (arg->type != STACK_I4 && arg->type != STACK_PTR)
return 1;
return 0;
- case MONO_TYPE_CLASS:
- case MONO_TYPE_STRING:
case MONO_TYPE_OBJECT:
+ if (arg->type != STACK_OBJ)
+ return 1;
+ return 0;
+ case MONO_TYPE_STRING:
+ if (arg->type != STACK_OBJ)
+ return 1;
+ /* ldnull has arg->klass unset */
+ /*if (arg->klass && arg->klass != mono_defaults.string_class) {
+ G_BREAKPOINT ();
+ return 1;
+ }*/
+ return 0;
+ case MONO_TYPE_CLASS:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
if (arg->type != STACK_OBJ)
/* FIXME: check type compatibility */
return 0;
}
+ case MONO_TYPE_VAR:
+ case MONO_TYPE_MVAR:
+ /* FIXME: all the arguments must be references for now,
+ * later look inside cfg and see if the arg num is
+ * really a reference
+ */
+ g_assert (cfg->generic_sharing_context);
+ if (arg->type != STACK_OBJ)
+ return 1;
+ return 0;
default:
g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
}
call->inst.opcode = CEE_CALL;
temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
} else {
- type_to_eval_stack_type (ret, ins);
+ type_to_eval_stack_type (cfg, ret, ins);
temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
}
MONO_ADD_INS (bblock, ins);
} else {
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
+ /* FIXME: handle CEE_STIND_R4 */
store->cil_code = ip;
if (to_end)
mono_add_ins_to_end (bblock, store);
{
int i;
for (i = 0; i < sig->param_count; ++i) {
- if (sig->params [i]->type == MONO_TYPE_R4) {
+ if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
MonoInst *iargs [1];
int temp;
iargs [0] = args [i + sig->hasthis];
call->args = args;
call->signature = sig;
call = mono_arch_call_opcode (cfg, bblock, call, virtual);
- type_to_eval_stack_type (sig->ret, &call->inst);
+ type_to_eval_stack_type (cfg, sig->ret, &call->inst);
for (arg = call->out_args; arg;) {
MonoInst *narg = arg->next;
temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
temp->flags |= MONO_INST_IS_TEMP;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
+ /* FIXME: handle CEE_STIND_R4 */
store->cil_code = tree->cil_code;
} else {
store = ins;
}
}
+/*
+ * This entry point could be used later for arbitrary method
+ * redirection.
+ */
+inline static int
+mini_redirect_call (int *temp, MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
+ MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
+{
+
+ if (method->klass == mono_defaults.string_class) {
+ /* managed string allocation support */
+ if (strcmp (method->name, "InternalAllocateStr") == 0) {
+ MonoInst *iargs [2];
+ MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
+ MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
+ if (!managed_alloc)
+ return FALSE;
+ NEW_VTABLECONST (cfg, iargs [0], vtable);
+ iargs [1] = args [0];
+ *temp = mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, this);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
static MonoMethodSignature *
mono_get_array_new_va_signature (int arity)
{
int temp; \
NEW_LOCLOADA (cfg, (ins), (idx)); \
handle_store_float (cfg, bblock, (ins), *sp, (ip)); \
- MONO_INST_NEW (cfg, (ins), CEE_NOP); \
+ MONO_INST_NEW (cfg, (ins), OP_NOP); \
} \
} while (0)
#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
int temp; \
NEW_ARGLOADA (cfg, (ins), (idx)); \
handle_store_float (cfg, bblock, (ins), *sp, (ip)); \
- MONO_INST_NEW (cfg, (ins), CEE_NOP); \
+ MONO_INST_NEW (cfg, (ins), OP_NOP); \
} \
} while (0)
#else
NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
MONO_ADD_INS (bblock, inst);
}
- MONO_INST_NEW (cfg, inst, OP_MEMCPY);
- inst->inst_left = dest;
- inst->inst_right = src;
- inst->cil_code = ip;
- inst->backend.size = n;
+ NEW_MEMCPY (cfg, inst, dest, src, n, align);
MONO_ADD_INS (bblock, inst);
return;
}
MonoInst *iargs [3];
MonoInst *ins, *zero_int32;
int n;
+ guint32 align;
MonoMethod *memset_method;
NEW_ICONST (cfg, zero_int32, 0);
mono_class_init (klass);
- n = mono_class_value_size (klass, NULL);
+ n = mono_class_value_size (klass, &align);
MONO_INST_NEW (cfg, ins, 0);
ins->cil_code = ip;
ins->inst_left = dest;
ins->inst_right = zero_int32;
- switch (n) {
- case 1:
+ if (n == 1) {
ins->opcode = CEE_STIND_I1;
MONO_ADD_INS (bblock, ins);
- break;
- case 2:
+ } else if ((n == 2) && (align >= 2)) {
ins->opcode = CEE_STIND_I2;
MONO_ADD_INS (bblock, ins);
- break;
- case 4:
+ } else if ((n == 2) && (align >= 4)) {
ins->opcode = CEE_STIND_I4;
MONO_ADD_INS (bblock, ins);
- break;
- default:
- if (n <= sizeof (gpointer) * 5) {
- ins->opcode = OP_MEMSET;
- ins->inst_imm = 0;
- ins->backend.size = n;
- MONO_ADD_INS (bblock, ins);
- break;
- }
+ } else if (n <= sizeof (gpointer) * 5) {
+ NEW_MEMSET (cfg, ins, dest, 0, n, align);
+ MONO_ADD_INS (bblock, ins);
+ } else {
memset_method = get_memset_method ();
handle_loaded_temps (cfg, bblock, stack_start, sp);
iargs [0] = dest;
NEW_ICONST (cfg, iargs [1], 0);
NEW_ICONST (cfg, iargs [2], n);
mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
- break;
}
}
return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
} else {
MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+ MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
gboolean pass_lw;
+ if (managed_alloc) {
+ NEW_VTABLECONST (cfg, iargs [0], vtable);
+ return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
+ }
alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
if (pass_lw) {
guint32 lw = vtable->klass->instance_size;
add->cil_code = ip;
add->klass = klass;
MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
- vstore->opcode = mono_type_to_stind (&klass->byval_arg);
+ vstore->opcode = mini_type_to_stind (cfg, &klass->byval_arg);
vstore->cil_code = ip;
vstore->inst_left = add;
vstore->inst_right = val;
}
#ifdef MONO_ARCH_SOFT_FLOAT
/* this complicates things, fix later */
- if (signature->params [i]->type == MONO_TYPE_R4)
+ if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
return FALSE;
#endif
}
return NULL;
}
+static int
+is_unsigned_regsize_type (MonoType *type)
+{
+ switch (type->type) {
+ case MONO_TYPE_U1:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_U4:
+#if SIZEOF_VOID_P == 8
+ /*case MONO_TYPE_U8: this requires different opcodes in inssel.brg */
+#endif
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
static MonoInst*
mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
return ins;
#endif
} else if (strcmp (cmethod->name, ".ctor") == 0) {
- MONO_INST_NEW (cfg, ins, CEE_NOP);
+ MONO_INST_NEW (cfg, ins, OP_NOP);
return ins;
} else
return NULL;
MonoInst *ldelem, *store, *load;
MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
int n;
- n = mono_type_to_stind (&eklass->byval_arg);
+ n = mini_type_to_stind (cfg, &eklass->byval_arg);
if (n == CEE_STOBJ)
return NULL;
sp [0] = args [0];
NEW_LDELEMA (cfg, ldelem, sp, eklass);
ldelem->flags |= MONO_INST_NORANGECHECK;
MONO_INST_NEW (cfg, store, n);
- n = mono_type_to_ldind (&eklass->byval_arg);
- MONO_INST_NEW (cfg, load, mono_type_to_ldind (&eklass->byval_arg));
- type_to_eval_stack_type (&eklass->byval_arg, load);
+ MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &eklass->byval_arg));
+ type_to_eval_stack_type (cfg, &eklass->byval_arg, load);
load->inst_left = ldelem;
store->inst_left = args [2];
store->inst_right = load;
return store;
+ } else if (cmethod->klass == mono_defaults.math_class) {
+ if (strcmp (cmethod->name, "Min") == 0) {
+ if (is_unsigned_regsize_type (fsig->params [0])) {
+ MONO_INST_NEW (cfg, ins, OP_MIN);
+ ins->inst_i0 = args [0];
+ ins->inst_i1 = args [1];
+ return ins;
+ }
+ } else if (strcmp (cmethod->name, "Max") == 0) {
+ if (is_unsigned_regsize_type (fsig->params [0])) {
+ MONO_INST_NEW (cfg, ins, OP_MAX);
+ ins->inst_i0 = args [0];
+ ins->inst_i1 = args [1];
+ return ins;
+ }
+ }
} else if (cmethod->klass->image == mono_defaults.corlib) {
if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
&& strcmp (cmethod->klass->name, "Debugger") == 0) {
- MONO_INST_NEW (cfg, ins, CEE_BREAK);
+ MONO_INST_NEW (cfg, ins, OP_BREAK);
+ return ins;
+ }
+ if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
+ && strcmp (cmethod->klass->name, "Environment") == 0) {
+#ifdef PLATFORM_WIN32
+ NEW_ICONST (cfg, ins, 1);
+#else
+ NEW_ICONST (cfg, ins, 0);
+#endif
return ins;
}
}
temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
*args++ = temp;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
+ /* FIXME: handle CEE_STIND_R4 */
store->cil_code = sp [0]->cil_code;
MONO_ADD_INS (bblock, store);
}
*args++ = temp;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
store->cil_code = sp [0]->cil_code;
+ /* FIXME: handle CEE_STIND_R4 */
if (store->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, store, temp->inst_c0);
handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
static int
inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
- guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
+ guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways, MonoGenericContext *shared_context)
{
MonoInst *ins, *rvar = NULL;
MonoMethodHeader *cheader;
MonoBasicBlock *ebblock, *sbblock;
int i, costs, new_locals_offset;
MonoMethod *prev_inlined_method;
+ MonoBasicBlock **prev_cil_offset_to_bb;
+ unsigned char* prev_cil_start;
+ guint32 prev_cil_offset_to_bb_len;
+
+ g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
+
#if (MONO_INLINE_CALLED_LIMITED_METHODS)
if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
return 0;
new_locals_offset = cfg->num_varinfo;
for (i = 0; i < cheader->num_locals; ++i)
mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
-
+
/* allocate starte and end blocks */
sbblock = NEW_BBLOCK (cfg);
sbblock->block_num = cfg->num_bblocks++;
prev_inlined_method = cfg->inlined_method;
cfg->inlined_method = cmethod;
+ prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
+ prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
+ prev_cil_start = cfg->cil_start;
- costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
+ costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT, shared_context);
cfg->inlined_method = prev_inlined_method;
+ cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
+ cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
+ cfg->cil_start = prev_cil_start;
if ((costs >= 0 && costs < 60) || inline_allways) {
if (cfg->verbose_level > 2)
mono_jit_stats.inlined_methods++;
/* always add some code to avoid block split failures */
- MONO_INST_NEW (cfg, ins, CEE_NOP);
+ MONO_INST_NEW (cfg, ins, OP_NOP);
MONO_ADD_INS (bblock, ins);
ins->cil_code = ip;
} else {
if (cfg->verbose_level > 2)
g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
+ cfg->exception_type = MONO_EXCEPTION_NONE;
}
return 0;
}
* or through repeated runs where the compiler applies offline the optimizations to
* each method and then decides if it was worth it.
*
- * TODO:
- * * consider using an array instead of an hash table (bb_hash)
*/
#define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
/* offset from br.s -> br like opcodes */
#define BIG_BRANCH_OFFSET 13
-static gboolean
+static inline gboolean
ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
{
- MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
+ MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
return b == NULL || b == bb;
}
static int
-get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
+get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
{
unsigned char *ip = start;
unsigned char *target;
break;
case MonoShortInlineBrTarget:
target = start + cli_addr + 2 + (signed char)ip [1];
- GET_BBLOCK (cfg, bbhash, bblock, target);
+ GET_BBLOCK (cfg, bblock, target);
ip += 2;
if (ip < end)
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
break;
case MonoInlineBrTarget:
target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
- GET_BBLOCK (cfg, bbhash, bblock, target);
+ GET_BBLOCK (cfg, bblock, target);
ip += 5;
if (ip < end)
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
break;
case MonoInlineSwitch: {
guint32 n = read32 (ip + 1);
ip += 5;
cli_addr += 5 + 4 * n;
target = start + cli_addr;
- GET_BBLOCK (cfg, bbhash, bblock, target);
+ GET_BBLOCK (cfg, bblock, target);
for (j = 0; j < n; ++j) {
target = start + cli_addr + (gint32)read32 (ip);
- GET_BBLOCK (cfg, bbhash, bblock, target);
+ GET_BBLOCK (cfg, bblock, target);
ip += 4;
}
break;
/* Find the start of the bblock containing the throw */
bblock = NULL;
while ((bb_start >= start) && !bblock) {
- bblock = g_hash_table_lookup (bbhash, (bb_start));
+ bblock = cfg->cil_offset_to_bb [(bb_start) - start];
bb_start --;
}
if (bblock)
temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
temp->flags |= MONO_INST_IS_TEMP;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
+ /* FIXME: handle CEE_STIND_R4 */
store->cil_code = ins->cil_code;
MONO_ADD_INS (bblock, store);
NEW_TEMPLOAD (cfg, load, temp->inst_c0);
method = mono_get_method_full (m->klass->image, token, klass, context);
- if (method && method->is_inflated)
- method = mono_get_inflated_method (method);
-
return method;
}
if (result == MONO_JIT_LINKDEMAND_ECMA) {
/* Generate code to throw a SecurityException before the actual call/link */
- MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
- MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (cfg->domain, assembly);
- MonoReflectionMethod *refmet = mono_method_get_object (cfg->domain, caller, NULL);
MonoSecurityManager *secman = mono_security_manager_get_methods ();
- MonoInst *args [3];
+ MonoInst *args [2];
NEW_ICONST (cfg, args [0], 4);
- NEW_PCONST (cfg, args [1], refass);
- NEW_PCONST (cfg, args [2], refmet);
+ NEW_METHODCONST (cfg, args [1], caller);
mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
} else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
/* don't hide previous results */
cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
cfg->exception_data = result;
+ return TRUE;
}
return FALSE;
}
-static gboolean
-can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
+static MonoMethod*
+method_access_exception (void)
{
- GSList *tmp;
- if (accessing == accessed)
- return TRUE;
- if (!accessed || !accessing)
- return FALSE;
- for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
- MonoAssemblyName *friend = tmp->data;
- /* Be conservative with checks */
- if (!friend->name)
- continue;
- if (strcmp (accessing->aname.name, friend->name))
- continue;
- if (friend->public_key_token [0]) {
- if (!accessing->aname.public_key_token [0])
- continue;
- if (strcmp ((char*)friend->public_key_token, (char*)accessing->aname.public_key_token))
- continue;
- }
- return TRUE;
+ static MonoMethod *method = NULL;
+
+ if (!method) {
+ MonoSecurityManager *secman = mono_security_manager_get_methods ();
+ method = mono_class_get_method_from_name (secman->securitymanager,
+ "MethodAccessException", 2);
}
- return FALSE;
+ g_assert (method);
+ return method;
}
-/* FIXME: check visibility of type, too */
-static gboolean
-can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
-{
- /* Partition I 8.5.3.2 */
- /* the access level values are the same for fields and methods */
- switch (access_level) {
- case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
- /* same compilation unit */
- return access_klass->image == member_klass->image;
- case FIELD_ATTRIBUTE_PRIVATE:
- if (access_klass->generic_class && member_klass->generic_class && member_klass->generic_class->container_class)
- return member_klass->generic_class->container_class == access_klass->generic_class->container_class;
- return access_klass == member_klass;
- case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
- if (mono_class_has_parent (access_klass, member_klass) &&
- can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
- return TRUE;
- return FALSE;
- case FIELD_ATTRIBUTE_ASSEMBLY:
- return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
- case FIELD_ATTRIBUTE_FAMILY:
- if (mono_class_has_parent (access_klass, member_klass))
- return TRUE;
- return FALSE;
- case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
- if (mono_class_has_parent (access_klass, member_klass))
- return TRUE;
- return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
- case FIELD_ATTRIBUTE_PUBLIC:
- return TRUE;
+static void
+emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
+ MonoBasicBlock *bblock, unsigned char *ip)
+{
+ MonoMethod *thrower = method_access_exception ();
+ MonoInst *args [2];
+
+ NEW_METHODCONST (cfg, args [0], caller);
+ NEW_METHODCONST (cfg, args [1], callee);
+ mono_emit_method_call_spilled (cfg, bblock, thrower,
+ mono_method_signature (thrower), args, ip, NULL);
+}
+
+static MonoMethod*
+verification_exception (void)
+{
+ static MonoMethod *method = NULL;
+
+ if (!method) {
+ MonoSecurityManager *secman = mono_security_manager_get_methods ();
+ method = mono_class_get_method_from_name (secman->securitymanager,
+ "VerificationException", 0);
}
- return FALSE;
+ g_assert (method);
+ return method;
}
-static gboolean
-can_access_field (MonoMethod *method, MonoClassField *field)
+static void
+emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
{
- /* FIXME: check all overlapping fields */
- int can = can_access_member (method->klass, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
- if (!can) {
- MonoClass *nested = method->klass->nested_in;
- while (nested) {
- can = can_access_member (nested, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
- if (can)
- return TRUE;
- nested = nested->nested_in;
- }
+ MonoMethod *thrower = verification_exception ();
+
+ mono_emit_method_call_spilled (cfg, bblock, thrower,
+ mono_method_signature (thrower),
+ NULL, ip, NULL);
+}
+
+static void
+ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
+ MonoBasicBlock *bblock, unsigned char *ip)
+{
+ MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
+ MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
+ gboolean is_safe = TRUE;
+
+ if (!(caller_level >= callee_level ||
+ caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
+ callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
+ is_safe = FALSE;
}
- return can;
+
+ if (!is_safe)
+ emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
}
static gboolean
-can_access_method (MonoMethod *method, MonoMethod *called)
+method_is_safe (MonoMethod *method)
{
- int can = can_access_member (method->klass, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
- if (!can) {
- MonoClass *nested = method->klass->nested_in;
- while (nested) {
- can = can_access_member (nested, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
- if (can)
- return TRUE;
- nested = nested->nested_in;
- }
- }
- /*
- * FIXME:
- * with generics calls to explicit interface implementations can be expressed
- * directly: the method is private, but we must allow it. This may be opening
- * a hole or the generics code should handle this differently.
- * Maybe just ensure the interface type is public.
- */
- if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
- return TRUE;
- return can;
+ /*
+ if (strcmp (method->name, "unsafeMethod") == 0)
+ return FALSE;
+ */
+ return TRUE;
}
/*
if (newarr->inst_newa_len->opcode != OP_ICONST)
return NULL;
cmethod = mini_get_method (method, token, NULL, NULL);
+ if (!cmethod)
+ return NULL;
if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
return NULL;
switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
return NULL;
}
+static void
+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);
+ 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);
+}
+
/*
* mono_method_to_ir: translates IL into basic blocks containing trees
*/
static int
mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
- guint inline_offset, gboolean is_virtual_call)
+ guint inline_offset, gboolean is_virtual_call, MonoGenericContext *shared_context)
{
MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
MonoInst *ins, **sp, **stack_start;
MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
- GHashTable *bbhash;
MonoMethod *cmethod;
MonoInst **arg_array;
MonoMethodHeader *header;
dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
+ /* turn off visibility checks for smcs */
+ dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
+
/* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
sig = mono_method_signature (method);
num_args = sig->hasthis + sig->param_count;
ip = (unsigned char*)header->code;
+ cfg->cil_start = ip;
end = ip + header->code_size;
mono_jit_stats.cil_code_size += header->code_size;
- if (sig->is_inflated)
+ if (cfg->generic_sharing_context) {
+ g_assert (shared_context);
+ generic_context = shared_context;
+ } else if (sig->is_inflated)
generic_context = mono_method_get_context (method);
else if (generic_container)
generic_context = &generic_container->context;
g_assert (!sig->has_type_parameters);
- if (cfg->method == method) {
+ if (cfg->method == method)
real_offset = 0;
- bbhash = cfg->bb_hash;
- } else {
+ else
real_offset = inline_offset;
- bbhash = g_hash_table_new (g_direct_hash, NULL);
- }
+
+ cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
+ cfg->cil_offset_to_bb_len = header->code_size;
if (cfg->verbose_level > 2)
g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
for (i = 0; i < header->num_clauses; ++i) {
MonoBasicBlock *try_bb;
MonoExceptionClause *clause = &header->clauses [i];
- GET_BBLOCK (cfg, bbhash, try_bb, ip + clause->try_offset);
+ GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
try_bb->real_offset = clause->try_offset;
- GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
+ GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
tblock->real_offset = clause->handler_offset;
tblock->flags |= BB_EXCEPTION_HANDLER;
MONO_ADD_INS (tblock, dummy_use);
if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
- GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
+ GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
tblock->real_offset = clause->data.filter_offset;
tblock->in_scount = 1;
tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
bblock = NEW_BBLOCK (cfg);
bblock->cil_code = ip;
- ADD_BBLOCK (cfg, bbhash, bblock);
+ ADD_BBLOCK (cfg, bblock);
if (cfg->method == method) {
breakpoint_id = mono_debugger_method_has_breakpoint (method);
if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
- MONO_INST_NEW (cfg, ins, CEE_BREAK);
+ MONO_INST_NEW (cfg, ins, OP_BREAK);
MONO_ADD_INS (bblock, ins);
}
}
- if (mono_use_security_manager)
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
secman = mono_security_manager_get_methods ();
security = (secman && mono_method_has_declsec (method));
if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
pinvoke = FALSE;
}
+ if (custom)
+ mono_custom_attrs_free (custom);
if (pinvoke) {
custom = mono_custom_attrs_from_class (wrapped->klass);
if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
pinvoke = FALSE;
}
+ if (custom)
+ mono_custom_attrs_free (custom);
}
} else {
/* not a P/Invoke after all */
mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
}
- if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
+ if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+ MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
+ if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+ if (!(method->klass && method->klass->image &&
+ mono_security_core_clr_is_platform_image (method->klass->image))) {
+ emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
+ }
+ }
+ }
+ if (!method_is_safe (method))
+ emit_throw_verification_exception (cfg, bblock, ip);
+ }
+
+ if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
ip = err_pos;
UNVERIFIED;
}
if (start_new_bblock == 2) {
g_assert (ip == tblock->cil_code);
} else {
- GET_BBLOCK (cfg, bbhash, tblock, ip);
+ GET_BBLOCK (cfg, tblock, ip);
}
bblock->next_bb = tblock;
bblock = tblock;
g_slist_free (class_inits);
class_inits = NULL;
} else {
- if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
+ if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
link_bblock (cfg, bblock, tblock);
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
switch (*ip) {
case CEE_NOP:
+ MONO_INST_NEW (cfg, ins, OP_NOP);
+ ins->cil_code = ip++;
+ MONO_ADD_INS (bblock, ins);
+ break;
case CEE_BREAK:
- MONO_INST_NEW (cfg, ins, *ip);
+ MONO_INST_NEW (cfg, ins, OP_BREAK);
ins->cil_code = ip++;
MONO_ADD_INS (bblock, ins);
break;
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);
handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
CHECK_OPSIZE (5);
if (stack_start != sp)
UNVERIFIED;
- MONO_INST_NEW (cfg, ins, CEE_JMP);
+ 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);
if (!cmethod)
goto load_error;
- if (mono_use_security_manager) {
+ if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod, generic_context))
+ GENERIC_SHARING_FAILURE;
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
if (check_linkdemand (cfg, method, cmethod, bblock, ip))
INLINE_FAILURE;
+ CHECK_CFG_EXCEPTION;
}
ins->inst_p0 = cmethod;
cil_method = cmethod;
} else if (constrained_call) {
cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
- cmethod = mono_get_inflated_method (cmethod);
+ cil_method = cmethod;
} else {
cmethod = mini_get_method (method, token, NULL, generic_context);
cil_method = cmethod;
if (!cmethod)
goto load_error;
- if (!dont_verify && !cfg->skip_visibility && !can_access_method (method, cil_method))
- UNVERIFIED;
+ if (!dont_verify && !cfg->skip_visibility && !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);
if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
/* MS.NET seems to silently convert this to a callvirt */
fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
}
+ mono_save_token_info (cfg, image, token, cmethod);
+
n = fsig->param_count + fsig->hasthis;
- if (mono_use_security_manager) {
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
if (check_linkdemand (cfg, method, cmethod, bblock, ip))
INLINE_FAILURE;
+ CHECK_CFG_EXCEPTION;
}
if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
if (cmethod && cmethod->klass->generic_container)
UNVERIFIED;
+ if (cfg->generic_sharing_context && cmethod && mono_method_check_context_used (cmethod, generic_context))
+ GENERIC_SHARING_FAILURE;
+
CHECK_STACK (n);
//g_assert (!virtual || fsig->hasthis);
* sp [0] is a pointer to the data: we need the value
* in handle_box (), so load it here.
*/
- MONO_INST_NEW (cfg, load, mono_type_to_ldind (&constrained_call->byval_arg));
- type_to_eval_stack_type (&constrained_call->byval_arg, load);
+ 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);
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_PCONST (cfg, iargs [1], cmethod);
+ 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);
/* FIXME: This assumes the two methods has the same number and type of arguments */
/*
* We implement tail calls by storing the actual arguments into the
- * argument variables, then emitting a CEE_JMP. Since the actual arguments
+ * argument variables, then emitting a OP_JMP. Since the actual arguments
* can refer to the arg variables, we have to spill them.
*/
handle_loaded_temps (cfg, bblock, sp, sp + n);
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);
handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
else
MONO_ADD_INS (bblock, ins);
}
- MONO_INST_NEW (cfg, ins, CEE_JMP);
+ MONO_INST_NEW (cfg, ins, OP_JMP);
ins->cil_code = ip;
ins->inst_p0 = cmethod;
ins->inst_p1 = arg_array [0];
if (MONO_TYPE_IS_VOID (fsig->ret)) {
MONO_ADD_INS (bblock, ins);
} else {
- type_to_eval_stack_type (fsig->ret, ins);
+ type_to_eval_stack_type (cfg, fsig->ret, ins);
*sp = ins;
sp++;
}
allways = TRUE;
}
- if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
+ if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways, shared_context))) {
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
if (!has_vtargs) {
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, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
tblock = start_bblock->out_bb [0];
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 {
} else {
/* Prevent inlining of methods which call other methods */
INLINE_FAILURE;
- if (ip_in_bb (cfg, bblock, ip + 5)
+ if (mini_redirect_call (&temp, cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) {
+ if (temp != -1) {
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ sp++;
+ }
+ } else if (ip_in_bb (cfg, bblock, ip + 5)
&& (!MONO_TYPE_ISSTRUCT (fsig->ret))
&& (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
&& (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET)) {
//g_assert (returnvar != -1);
NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
store->cil_code = sp [0]->cil_code;
+ /* FIXME: handle CEE_STIND_R4 */
if (store->opcode == CEE_STOBJ) {
g_assert_not_reached ();
NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
g_assert (!return_var);
CHECK_STACK (1);
--sp;
- MONO_INST_NEW (cfg, ins, CEE_NOP);
- ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
+ MONO_INST_NEW (cfg, ins, OP_NOP);
+ ins->opcode = mini_type_to_stind (cfg, mono_method_signature (method)->ret);
if (ins->opcode == CEE_STOBJ) {
NEW_RETLOADA (cfg, ins);
/* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
}
if (sp != stack_start)
UNVERIFIED;
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip++;
ins->inst_target_bb = end_bblock;
MONO_ADD_INS (bblock, ins);
break;
case CEE_BR_S:
CHECK_OPSIZE (2);
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip++;
MONO_ADD_INS (bblock, ins);
target = ip + 1 + (signed char)(*ip);
++ip;
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
CHECK_BBLOCK (target, ip, tblock);
ins->inst_target_bb = tblock;
break;
case CEE_BR:
CHECK_OPSIZE (5);
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip++;
MONO_ADD_INS (bblock, ins);
target = ip + 4 + (gint32)read32(ip);
ip += 4;
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
CHECK_BBLOCK (target, ip, tblock);
ins->inst_target_bb = tblock;
CHECK_OPSIZE (n * sizeof (guint32));
target = ip + n * sizeof (guint32);
MONO_ADD_INS (bblock, ins);
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
ins->klass = GUINT_TO_POINTER (n);
ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
ins->inst_many_bb [n] = tblock;
for (i = 0; i < n; ++i) {
- GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
+ GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
link_bblock (cfg, bblock, tblock);
ins->inst_many_bb [i] = tblock;
ip += 4;
store->inst_i1 = load;
store->flags |= ins_flag;
} else {
- n = mono_class_value_size (klass, NULL);
+ guint32 align;
+
+ n = mono_class_value_size (klass, &align);
if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
MonoInst *copy;
- MONO_INST_NEW (cfg, copy, OP_MEMCPY);
- copy->inst_left = sp [0];
- copy->inst_right = sp [1];
- copy->cil_code = ip;
- copy->backend.size = n;
+ NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, align);
MONO_ADD_INS (bblock, copy);
} else {
MonoMethod *memcpy_method = get_memcpy_method ();
MonoInst *iargs [3];
int loc_index = -1;
int stloc_len = 0;
+ guint32 align;
+
CHECK_OPSIZE (5);
CHECK_STACK (1);
--sp;
CHECK_LOCAL (loc_index);
NEW_LOCSTORE (cfg, ins, loc_index, *sp);
+ /* FIXME: handle CEE_STIND_R4 */
if (ins->opcode == CEE_STOBJ) {
handle_loaded_temps (cfg, bblock, stack_start, sp);
ins->cil_code = ip;
}
}
- n = mono_class_value_size (klass, NULL);
+ n = mono_class_value_size (klass, &align);
ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
MonoInst *copy;
- MONO_INST_NEW (cfg, copy, OP_MEMCPY);
- copy->inst_left = iargs [0];
- copy->inst_right = *sp;
- copy->cil_code = ip;
- copy->backend.size = n;
+ NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
MONO_ADD_INS (bblock, copy);
} else {
MonoMethod *memcpy_method = get_memcpy_method ();
n = read32 (ip + 1);
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;
MonoInst* domain_var;
if (cfg->compile_aot) {
+ /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
}
/* avoid depending on undefined C behavior in sequence points */
MonoInst *iargs [2];
MonoMethodSignature *fsig;
int temp;
-
+
CHECK_OPSIZE (5);
token = read32 (ip + 1);
cmethod = mini_get_method (method, token, NULL, generic_context);
goto load_error;
fsig = mono_method_get_signature (cmethod, image, token);
+ mono_save_token_info (cfg, image, token, cmethod);
+
if (!mono_class_init (cmethod->klass))
goto load_error;
- if (mono_use_security_manager) {
+ if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod, generic_context))
+ GENERIC_SHARING_FAILURE;
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
if (check_linkdemand (cfg, method, cmethod, bblock, ip))
INLINE_FAILURE;
+ CHECK_CFG_EXCEPTION;
+ } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
+ ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
}
n = fsig->param_count;
!g_list_find (dont_inline, cmethod)) {
int costs;
MonoBasicBlock *ebblock;
- if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
+ if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE, shared_context))) {
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
+ if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+ GENERIC_SHARING_FAILURE;
+
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
iargs [0] = sp [0];
costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock,
- iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+ iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
g_assert (costs > 0);
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
case CEE_UNBOX_ANY: {
MonoInst *add, *vtoffset;
MonoInst *iargs [3];
+ guint32 align;
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_context))
+ GENERIC_SHARING_FAILURE;
+
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
/* CASTCLASS */
if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
iargs [0] = sp [0];
costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
- iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+ iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
g_assert (costs > 0);
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
*sp = add;
ip += 5;
/* LDOBJ impl */
- n = mono_class_value_size (klass, NULL);
+ n = mono_class_value_size (klass, &align);
ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
MonoInst *copy;
- MONO_INST_NEW (cfg, copy, OP_MEMCPY);
- copy->inst_left = iargs [0];
- copy->inst_right = *sp;
- copy->cil_code = ip;
- copy->backend.size = n;
+ NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
MONO_ADD_INS (bblock, copy);
} else {
MonoMethod *memcpy_method = get_memcpy_method ();
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
+ if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+ GENERIC_SHARING_FAILURE;
+
if (mono_class_is_nullable (klass)) {
int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
NEW_TEMPLOAD (cfg, *sp, v);
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
+ if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+ GENERIC_SHARING_FAILURE;
+
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
iargs [0] = sp [0];
costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
- iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+ iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
g_assert (costs > 0);
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
break;
case CEE_THROW:
CHECK_STACK (1);
- MONO_INST_NEW (cfg, ins, *ip);
+ MONO_INST_NEW (cfg, ins, OP_THROW);
--sp;
ins->inst_left = *sp;
ins->cil_code = ip++;
if (!field)
goto load_error;
mono_class_init (klass);
- if (!dont_verify && !cfg->skip_visibility && !can_access_field (method, field))
- UNVERIFIED;
+ if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
+ FIELD_ACCESS_FAILURE;
foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
/* FIXME: mark instructions for use in SSA */
if (cfg->opt & MONO_OPT_INLINE) {
costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock,
- iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+ iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
g_assert (costs > 0);
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
}
#if HAVE_WRITE_BARRIERS
- } else if (mono_type_to_stind (field->type) == CEE_STIND_REF) {
+ } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF) {
/* insert call to write barrier */
MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
MonoInst *iargs [2];
mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
#endif
#ifdef MONO_ARCH_SOFT_FLOAT
- } else if (mono_type_to_stind (field->type) == CEE_STIND_R4) {
+ } 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_right = offset_ins;
ins->type = STACK_MP;
- MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
+ 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];
NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock,
- iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
+ iargs, ip, real_offset, dont_inline, &ebblock, TRUE, shared_context);
g_assert (costs > 0);
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
*sp++ = ins;
} else {
MonoInst *load;
- MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
- type_to_eval_stack_type (field->type, 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;
#ifdef MONO_ARCH_SOFT_FLOAT
- if (mono_type_to_ldind (field->type) == CEE_LDIND_R4) {
+ if (mini_type_to_ldind (cfg, field->type) == CEE_LDIND_R4) {
int temp;
temp = handle_load_float (cfg, bblock, ins, ip);
NEW_TEMPLOAD (cfg, *sp, temp);
if (!field)
goto load_error;
mono_class_init (klass);
+ if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
+ FIELD_ACCESS_FAILURE;
+
+ if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+ GENERIC_SHARING_FAILURE;
g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
MonoInst *store;
CHECK_STACK (1);
sp--;
- MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
+ 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;
ins_flag = 0;
+ /* FIXME: handle CEE_STIND_R4 */
if (store->opcode == CEE_STOBJ) {
handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
} else
case MONO_TYPE_FNPTR:
case MONO_TYPE_ARRAY:
NEW_PCONST (cfg, *sp, *((gpointer *)addr));
- type_to_eval_stack_type (field->type, *sp);
+ type_to_eval_stack_type (cfg, field->type, *sp);
sp++;
break;
#endif
if (!is_const) {
MonoInst *load;
CHECK_STACK_OVF (1);
- MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
- type_to_eval_stack_type (field->type, 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;
*sp++ = load;
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
- n = mono_type_to_stind (&klass->byval_arg);
+ n = mini_type_to_stind (cfg, &klass->byval_arg);
+ /* FIXME: handle CEE_STIND_R4 */
if (n == CEE_STOBJ) {
handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
} else {
break;
case CEE_BOX: {
MonoInst *val;
+
CHECK_STACK (1);
--sp;
val = *sp;
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
+ if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+ GENERIC_SHARING_FAILURE;
+
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
*sp++ = val;
ip += 5;
ins->cil_code = ip;
ins->inst_i0 = *sp;
ip += 5;
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
if (*ip == CEE_BRTRUE_S) {
target = ip + 4 + (gint)(read32 (ip));
ip += 4;
}
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
CHECK_BBLOCK (target, ip, tblock);
ins->inst_target_bb = tblock;
+ GET_BBLOCK (cfg, tblock, ip);
+ link_bblock (cfg, bblock, tblock);
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
inline_costs += 1;
break;
}
- case CEE_NEWARR:
+ case CEE_NEWARR: {
+ int context_used;
+
CHECK_STACK (1);
MONO_INST_NEW (cfg, ins, *ip);
ins->cil_code = ip;
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
+
+ if (cfg->generic_sharing_context)
+ context_used = mono_class_check_context_used (klass, generic_context);
+ else
+ context_used = 0;
+
+ if (context_used)
+ GENERIC_SHARING_FAILURE;
+
ins->inst_newa_class = klass;
ins->inst_newa_len = *sp;
ins->type = STACK_OBJ;
- ins->klass = klass;
+ ins->klass = mono_array_class_get (klass, 1);
ip += 5;
*sp++ = ins;
/*
}
inline_costs += 1;
break;
+ }
case CEE_LDLEN:
CHECK_STACK (1);
--sp;
UNVERIFIED;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
- klass = mono_class_get_full (image, token, generic_context);
+ klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
mono_class_init (klass);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
- MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
+ 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 (&klass->byval_arg, ins);
+ type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
ip += 5;
break;
}
sp -= 2;
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
- klass = array_access_to_klass (*ip);
+ klass = array_access_to_klass (*ip, sp [0]);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
#ifdef MONO_ARCH_SOFT_FLOAT
sp -= 3;
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
- klass = array_access_to_klass (*ip);
+ klass = array_access_to_klass (*ip, sp [0]);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
#ifdef MONO_ARCH_SOFT_FLOAT
UNVERIFIED;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
- klass = mono_class_get_full (image, token, generic_context);
+ klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
mono_class_init (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
- MonoMethod* helper = mono_marshal_get_stelemref ();
- MonoInst *iargs [3];
- handle_loaded_temps (cfg, bblock, stack_start, sp);
+ /* 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 {
+ MonoMethod* helper = mono_marshal_get_stelemref ();
+ MonoInst *iargs [3];
+ handle_loaded_temps (cfg, bblock, stack_start, sp);
- iargs [2] = sp [2];
- iargs [1] = sp [1];
- iargs [0] = sp [0];
-
- mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+ iargs [2] = sp [2];
+ iargs [1] = sp [1];
+ iargs [0] = sp [0];
+
+ mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+ }
} else {
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
- n = mono_type_to_stind (&klass->byval_arg);
+ n = mini_type_to_stind (cfg, &klass->byval_arg);
+ /* FIXME: CEE_STIND_R4 */
if (n == CEE_STOBJ)
handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
else {
handle_loaded_temps (cfg, bblock, stack_start, sp);
- iargs [2] = sp [2];
- iargs [1] = sp [1];
- iargs [0] = sp [0];
+ /* 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 {
+ iargs [2] = sp [2];
+ iargs [1] = sp [1];
+ iargs [0] = sp [0];
- mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
-
- /*
- MonoInst *group;
- NEW_GROUP (cfg, group, sp [0], sp [1]);
- MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
- ins->cil_code = ip;
- ins->inst_left = group;
- ins->inst_right = sp [2];
- MONO_ADD_INS (bblock, ins);
- */
+ mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+ inline_costs += 1;
+ }
++ip;
- inline_costs += 1;
break;
}
case CEE_CKFINITE: {
* this check */
- MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
+ 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);
mono_class_init (klass);
ins->cil_code = ip;
+ if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+ GENERIC_SHARING_FAILURE;
+
loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
}
else {
handle = mono_ldtoken (image, n, &handle_class, generic_context);
+ if (cfg->generic_sharing_context &&
+ mono_class_check_context_used (handle_class, generic_context))
+ GENERIC_SHARING_FAILURE;
}
if (!handle)
goto load_error;
int temp;
MonoInst *res, *store, *addr, *vtvar, *iargs [3];
+ GENERIC_SHARING_FAILURE;
+
vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
NEW_IMAGECONST (cfg, iargs [0], image);
ip++;
break;
case CEE_ENDFINALLY:
- MONO_INST_NEW (cfg, ins, *ip);
+ MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
MONO_ADD_INS (bblock, ins);
ins->cil_code = ip++;
start_new_bblock = 1;
g_list_free (handlers);
}
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
CHECK_BBLOCK (target, ip, tblock);
ins->inst_target_bb = tblock;
if (sp != stack_start)
UNVERIFIED;
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip;
ins->inst_target_bb = end_bblock;
MONO_ADD_INS (bblock, ins);
bblock->out_of_line = TRUE;
ip += 2;
break;
+ case CEE_MONO_TLS:
+ CHECK_STACK_OVF (1);
+ 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;
+ break;
default:
g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
break;
}
case CEE_LDFTN: {
MonoInst *argconst;
+ MonoMethod *cil_method;
int temp;
CHECK_STACK_OVF (1);
goto load_error;
mono_class_init (cmethod->klass);
- if (mono_use_security_manager) {
+ if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod, generic_context))
+ GENERIC_SHARING_FAILURE;
+
+ cil_method = cmethod;
+ if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
+ METHOD_ACCESS_FAILURE;
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
if (check_linkdemand (cfg, method, cmethod, bblock, ip))
INLINE_FAILURE;
+ CHECK_CFG_EXCEPTION;
+ } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
+ ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
}
handle_loaded_temps (cfg, bblock, stack_start, sp);
goto load_error;
mono_class_init (cmethod->klass);
- if (mono_use_security_manager) {
+ if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod, generic_context))
+ GENERIC_SHARING_FAILURE;
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
if (check_linkdemand (cfg, method, cmethod, bblock, ip))
INLINE_FAILURE;
+ CHECK_CFG_EXCEPTION;
+ } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
+ ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
}
handle_loaded_temps (cfg, bblock, stack_start, sp);
token = read32 (ip + 2);
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
+
+ if (cfg->generic_sharing_context && mono_class_check_context_used (klass, generic_context))
+ GENERIC_SHARING_FAILURE;
+
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MonoInst *store, *load;
NEW_PCONST (cfg, load, NULL);
sp -= 3;
if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
MonoInst *copy;
- MONO_INST_NEW (cfg, copy, OP_MEMCPY);
- copy->inst_left = sp [0];
- copy->inst_right = sp [1];
- copy->cil_code = ip;
- copy->backend.size = n;
+ NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, 0);
MONO_ADD_INS (bblock, copy);
ip += 2;
break;
break;
}
case CEE_SIZEOF:
+ GENERIC_SHARING_FAILURE;
+
CHECK_STACK_OVF (1);
CHECK_OPSIZE (6);
token = read32 (ip + 2);
for (tmp = bb_recheck; tmp; tmp = tmp->next) {
bblock = tmp->data;
/*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
- tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
+ tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
if (tblock != start_bblock) {
int l;
split_bblock (cfg, tblock, bblock);
if (cfg->verbose_level > 2)
g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
}
- } else {
- g_hash_table_destroy (bbhash);
}
g_slist_free (class_inits);
return inline_costs;
+ exception_exit:
+ g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
+ g_slist_free (class_inits);
+ dont_inline = g_list_remove (dont_inline, method);
+ return -1;
+
inline_failure:
- if (cfg->method != method)
- g_hash_table_destroy (bbhash);
g_slist_free (class_inits);
dont_inline = g_list_remove (dont_inline, method);
return -1;
load_error:
- if (cfg->method != method)
- g_hash_table_destroy (bbhash);
g_slist_free (class_inits);
dont_inline = g_list_remove (dont_inline, method);
cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
return -1;
unverified:
- if (cfg->method != method)
- g_hash_table_destroy (bbhash);
g_slist_free (class_inits);
dont_inline = g_list_remove (dont_inline, method);
- cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
- cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n",
- mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
+ set_exception_type_from_invalid_il (cfg, method, ip);
return -1;
}
}
case OP_RENAME:
case OP_RETARG:
- case CEE_NOP:
- case CEE_JMP:
- case CEE_BREAK:
+ case OP_NOP:
+ case OP_JMP:
+ case OP_BREAK:
break;
case OP_LOAD_MEMBASE:
case OP_LOADI4_MEMBASE:
case OP_LOADI2_MEMBASE:
printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
break;
- case CEE_BR:
+ case OP_BR:
case OP_CALL_HANDLER:
printf ("[B%d]", tree->inst_target_bb->block_num);
break;
#endif
static gpointer
-mono_create_delegate_trampoline (MonoMethod *method, gpointer addr)
+mono_create_delegate_trampoline (MonoClass *klass)
{
#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
+ MonoDomain *domain = mono_domain_get ();
gpointer code, ptr;
guint32 code_size;
- MonoDomain *domain = mono_domain_get ();
-
-#ifndef __ia64__
- code = mono_jit_find_compiled_method (domain, method);
- if (code)
- return code;
-#else
- /*
- * FIXME: We should return a function descriptor here but it is not stored
- * anywhere so it would be leaked.
- */
-#endif
mono_domain_lock (domain);
- ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, method);
+ ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, klass);
mono_domain_unlock (domain);
if (ptr)
return ptr;
- code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
+ code = mono_arch_create_specific_trampoline (klass, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size);
ptr = mono_create_ftnptr (domain, code);
/* store trampoline address */
mono_domain_lock (domain);
g_hash_table_insert (domain->delegate_trampoline_hash,
- method, ptr);
+ klass, ptr);
mono_domain_unlock (domain);
return ptr;
#else
- return addr;
+ return NULL;
#endif
}
mono_destroy_compile (MonoCompile *cfg)
{
//mono_mempool_stats (cfg->mempool);
- g_hash_table_destroy (cfg->bb_hash);
mono_free_loop_info (cfg);
if (cfg->rs)
mono_regstate_free (cfg->rs);
g_hash_table_destroy (cfg->exvars);
mono_mempool_destroy (cfg->mempool);
g_list_free (cfg->ldstr_list);
+ g_hash_table_destroy (cfg->token_info_hash);
g_free (cfg->varinfo);
g_free (cfg->vars);
/* handle_remove should be eventually called for this thread, too
g_free (jit_tls);*/
- mono_thread_exit ();
+ if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_LEGACY) ||
+ (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
+ mono_thread_exit ();
+ } else {
+ exit (mono_environment_exitcode_get ());
+ }
}
static void*
#endif
mono_arch_setup_jit_tls_data (jit_tls);
-
-#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
mono_setup_altstack (jit_tls);
-#endif
return jit_tls;
}
{
MonoThread *thread;
void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
+ mono_debugger_thread_created (tid, jit_tls);
thread = mono_thread_current ();
if (thread)
thread->jit_data = jit_tls;
{
MonoThread *thread;
void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
+ mono_debugger_thread_created (tid, (MonoJitTlsData *) jit_tls);
thread = mono_thread_current ();
if (thread)
thread->jit_data = jit_tls;
MonoJitTlsData *jit_tls = thread->jit_data;
if (jit_tls) {
+ mono_debugger_thread_cleanup (jit_tls);
mono_arch_free_jit_tls_data (jit_tls);
-#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
mono_free_altstack (jit_tls);
-#endif
g_free (jit_tls->first_lmf);
g_free (jit_tls);
thread->jit_data = NULL;
case MONO_PATCH_INFO_LDTOKEN:
case MONO_PATCH_INFO_DECLSEC:
return (ji->type << 8) | ji->data.token->token;
+ case MONO_PATCH_INFO_VTABLE:
+ case MONO_PATCH_INFO_CLASS:
+ case MONO_PATCH_INFO_IID:
+ case MONO_PATCH_INFO_ADJUSTED_IID:
+ return (ji->type << 8) | (gssize)ji->data.klass;
+ case MONO_PATCH_INFO_FIELD:
+ case MONO_PATCH_INFO_SFLDA:
+ return (ji->type << 8) | (gssize)ji->data.field;
+ case MONO_PATCH_INFO_METHODCONST:
+ case MONO_PATCH_INFO_METHOD:
+ case MONO_PATCH_INFO_METHOD_JUMP:
+ return (ji->type << 8) | (gssize)ji->data.method;
+ case MONO_PATCH_INFO_IMAGE:
+ return (ji->type << 8) | (gssize)ji->data.image;
default:
return (ji->type << 8);
}
}
if (bb->last_ins != NULL) {
switch (bb->last_ins->opcode) {
- case CEE_BR:
+ case OP_BR:
if (bb->last_ins->inst_target_bb == orig) {
bb->last_ins->inst_target_bb = repl;
}
for (inst = bb->code; inst != NULL; inst = inst->next) {
switch (inst->opcode) {
- case CEE_NOP:
+ case OP_NOP:
break;
- case CEE_BR:
+ case OP_BR:
target_bb = inst->inst_target_bb;
break;
default:
if ((previous_bb != cfg->bb_entry) &&
(previous_bb->region == bb->region) &&
((previous_bb->last_ins == NULL) ||
- ((previous_bb->last_ins->opcode != CEE_BR) &&
+ ((previous_bb->last_ins->opcode != OP_BR) &&
(! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
(previous_bb->last_ins->opcode != CEE_SWITCH)))) {
for (i = 0; i < previous_bb->out_count; i++) {
if (previous_bb->out_bb [i] == target_bb) {
MonoInst *jump;
- MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_INST_NEW (cfg, jump, OP_BR);
MONO_ADD_INS (previous_bb, jump);
jump->cil_code = previous_bb->cil_code;
jump->inst_target_bb = target_bb;
/* Nullify branch at the end of bb */
if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
- bb->last_ins->opcode = CEE_NOP;
+ bb->last_ins->opcode = OP_NOP;
}
if (bb->last_ins) {
if (next && (!bb->last_ins || (bb->last_ins->opcode != OP_NOT_REACHED))) {
MonoInst *ins;
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
MONO_ADD_INS (bb, ins);
link_bblock (cfg, bb, next);
ins->inst_target_bb = next;
return FALSE;
condb->opcode = get_unsigned_condbranch (condb->opcode);
/* change the original condbranch to just point to the new unsigned check */
- bb->last_ins->opcode = CEE_BR;
+ bb->last_ins->opcode = OP_BR;
bb->last_ins->inst_target_bb = falset;
replace_out_block (bb, truet, NULL);
replace_in_block (truet, bb, NULL);
if (bb->out_count == 1) {
bbn = bb->out_bb [0];
- /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
+ /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
MonoInst *pop;
MONO_INST_NEW (cfg, pop, CEE_POP);
MONO_INST_NEW (cfg, pop, CEE_POP);
pop->inst_left = bb->last_ins->inst_left->inst_right;
mono_add_ins_to_end (bb, pop);
- bb->last_ins->opcode = CEE_BR;
+ bb->last_ins->opcode = OP_BR;
bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
changed = TRUE;
if (cfg->verbose_level > 2)
/* the block are in sequence anyway ... */
/* branches to the following block can be removed */
- if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
- bb->last_ins->opcode = CEE_NOP;
+ if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
+ bb->last_ins->opcode = OP_NOP;
changed = TRUE;
if (cfg->verbose_level > 2)
g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
if (bb->out_count == 1) {
bbn = bb->out_bb [0];
- if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
+ if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
bbn = bb->last_ins->inst_target_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+ if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
bbn->code->inst_target_bb->region == bb->region) {
if (cfg->verbose_level > 2)
/* if mono_eval_cond_branch () is ever taken to handle
* non-constant values to compare, issue a pop here.
*/
- bb->last_ins->opcode = CEE_BR;
+ bb->last_ins->opcode = OP_BR;
bb->last_ins->inst_target_bb = taken_branch_target;
mono_unlink_bblock (cfg, bb, untaken_branch_target);
changed = TRUE;
continue;
}
bbn = bb->last_ins->inst_true_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+ if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
bbn->code->inst_target_bb->region == bb->region) {
if (cfg->verbose_level > 2)
g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n",
}
bbn = bb->last_ins->inst_false_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+ if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
bbn->code->inst_target_bb->region == bb->region) {
if (cfg->verbose_level > 2)
g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n",
if (cfg->verbose_level > 2)
g_print ("creating vars\n");
+ cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
+
if (sig->hasthis)
- mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
+ cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
for (i = 0; i < sig->param_count; ++i) {
- mono_compile_create_var (cfg, sig->params [i], OP_ARG);
+ cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
if (sig->params [i]->byref) {
cfg->disable_ssa = TRUE;
}
if (cfg->verbose_level > 2)
g_print ("creating locals\n");
+
for (i = 0; i < header->num_locals; ++i)
mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
if (cfg->verbose_level > 2)
bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
} else {
MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
- inst->opcode = CEE_BR;
+ inst->opcode = OP_BR;
inst->inst_target_bb = bb->last_ins->inst_false_bb;
mono_bblock_add_inst (bb, inst);
}
code = cfg->native_code + cfg->code_len;
code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
cfg->code_len = code - cfg->native_code;
+ g_assert (cfg->code_len < cfg->code_size);
}
mono_arch_emit_epilog (cfg);
break;
}
}
-
+
+#ifdef VALGRIND_JIT_REGISTER_MAP
+if (valgrind_register){
+ char* nm = mono_method_full_name (cfg->method, TRUE);
+ VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
+ g_free (nm);
+ }
+#endif
+
if (cfg->verbose_level > 0) {
char* nm = mono_method_full_name (cfg->method, TRUE);
g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n",
if (previous_bb->region == bb->region) {
if (previous_bb != cfg->bb_entry) {
/* If previous_bb "followed through" to bb, */
- /* keep it linked with a CEE_BR */
+ /* keep it linked with a OP_BR */
if ((previous_bb->last_ins == NULL) ||
- ((previous_bb->last_ins->opcode != CEE_BR) &&
+ ((previous_bb->last_ins->opcode != OP_BR) &&
(! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
(previous_bb->last_ins->opcode != CEE_SWITCH))) {
int i;
for (i = 0; i < previous_bb->out_count; i++) {
if (previous_bb->out_bb [i] == bb) {
MonoInst *jump;
- MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_INST_NEW (cfg, jump, OP_BR);
MONO_ADD_INS (previous_bb, jump);
jump->cil_code = previous_bb->cil_code;
jump->inst_target_bb = bb;
}
} else {
/* We cannot add any inst to the entry BB, so we must */
- /* put a new BB in the middle to hold the CEE_BR */
+ /* put a new BB in the middle to hold the OP_BR */
MonoInst *jump;
MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
new_bb_after_entry->block_num = cfg->num_bblocks++;
// new_bb_after_entry->real_offset = bb->real_offset;
new_bb_after_entry->region = bb->region;
- MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_INST_NEW (cfg, jump, OP_BR);
MONO_ADD_INS (new_bb_after_entry, jump);
jump->cil_code = bb->cil_code;
jump->inst_target_bb = bb;
MonoJitInfo *jinfo;
int dfn = 0, i, code_size_ratio;
gboolean deadce_has_run = FALSE;
+ gboolean try_generic_shared = (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method);
+ MonoGenericContext *shared_context;
mono_jit_stats.methods_compiled++;
if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
mono_profiler_method_jit (method);
+ if (opts & MONO_OPT_GSHARED) {
+ if (try_generic_shared)
+ mono_stats.generics_sharable_methods++;
+ else if (mono_method_is_generic_impl (method))
+ mono_stats.generics_unsharable_methods++;
+ }
+
+ restart_compile:
cfg = g_new0 (MonoCompile, 1);
cfg->method = method;
cfg->mempool = mono_mempool_new ();
cfg->opt = opts;
cfg->prof_options = mono_profiler_get_events ();
cfg->run_cctors = run_cctors;
- cfg->bb_hash = g_hash_table_new (NULL, NULL);
cfg->domain = domain;
cfg->verbose_level = mini_verbose;
cfg->compile_aot = compile_aot;
cfg->skip_visibility = method->skip_visibility;
+ if (try_generic_shared)
+ cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
+ cfg->token_info_hash = g_hash_table_new (NULL, NULL);
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);
*/
mono_compile_create_vars (cfg);
- if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
+ if (try_generic_shared)
+ shared_context = mono_make_shared_context (cfg, mono_method_get_context (method));
+ else
+ shared_context = NULL;
+
+ if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE, shared_context)) < 0) {
+ if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
+ mono_destroy_compile (cfg);
+ try_generic_shared = FALSE;
+ goto restart_compile;
+ }
+ g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
+
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 */
g_list_free (regs);
}
+ /* todo: remove code when we have verified that the liveness for try/catch blocks
+ * works perfectly
+ */
+ /*
+ * Currently, this can't be commented out since exception blocks are not
+ * processed during liveness analysis.
+ */
+ mono_liveness_handle_exception_clauses (cfg);
+
if (cfg->opt & MONO_OPT_LINEARS) {
GList *vars, *regs;
jinfo->used_regs = cfg->used_int_regs;
jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
+ jinfo->generic_shared = cfg->generic_sharing_context ? 1 : 0;
if (header->num_clauses) {
int i;
ei->exvar_offset = exvar ? exvar->inst_offset : 0;
if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
- tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
+ tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
g_assert (tblock);
ei->data.filter = cfg->native_code + tblock->native_offset;
} else {
ei->data.catch_class = ec->data.catch_class;
}
- tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
+ tblock = cfg->cil_offset_to_bb [ec->try_offset];
g_assert (tblock);
ei->try_start = cfg->native_code + tblock->native_offset;
g_assert (tblock->native_offset);
- tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
+ tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
g_assert (tblock);
ei->try_end = cfg->native_code + tblock->native_offset;
g_assert (tblock->native_offset);
- tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
+ tblock = cfg->cil_offset_to_bb [ec->handler_offset];
g_assert (tblock);
ei->handler_start = cfg->native_code + tblock->native_offset;
}
return cfg;
}
+static MonoMethod*
+method_get_declaring_generic_method (MonoMethod *method)
+{
+ MonoMethodInflated *inflated;
+
+ g_assert (method->is_inflated);
+
+ inflated = (MonoMethodInflated*)method;
+
+ return inflated->declaring;
+}
+
+static MonoJitInfo*
+lookup_generic_method (MonoDomain *domain, MonoMethod *method)
+{
+ MonoMethod *open_method;
+
+ if (!mono_method_is_generic_sharable_impl (method))
+ return NULL;
+
+ open_method = method_get_declaring_generic_method (method);
+
+ return mono_domain_lookup_shared_generic (domain, open_method);
+}
+
+static MonoJitInfo*
+lookup_method (MonoDomain *domain, MonoMethod *method)
+{
+ MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
+
+ if (ji != NULL)
+ return ji;
+
+ return lookup_generic_method (domain, method);
+}
+
static gpointer
mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
{
MonoCompile *cfg;
- GHashTable *jit_code_hash;
gpointer code = NULL;
MonoJitInfo *info;
- jit_code_hash = target_domain->jit_code_hash;
-
- method = mono_get_inflated_method (method);
-
#ifdef MONO_USE_AOT_COMPILER
if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
MonoDomain *domain = mono_domain_get ();
case MONO_EXCEPTION_NONE: break;
case MONO_EXCEPTION_TYPE_LOAD:
case MONO_EXCEPTION_MISSING_FIELD:
- case MONO_EXCEPTION_MISSING_METHOD: {
+ case MONO_EXCEPTION_MISSING_METHOD:
+ case MONO_EXCEPTION_FILE_NOT_FOUND: {
/* Throw a type load exception if needed */
MonoLoaderError *error = mono_loader_get_last_error ();
+ MonoException *ex;
if (error) {
- MonoException *ex = mono_loader_error_prepare_exception (error);
- mono_destroy_compile (cfg);
- mono_raise_exception (ex);
+ ex = mono_loader_error_prepare_exception (error);
} else {
if (cfg->exception_ptr) {
- MonoException *ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
- mono_destroy_compile (cfg);
- mono_raise_exception (ex);
+ ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
+ } else {
+ if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
+ ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
+ else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
+ ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
+ else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
+ ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
+ else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
+ ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FileNotFoundException", cfg->exception_message);
+ else
+ g_assert_not_reached ();
}
- g_assert_not_reached ();
}
+ mono_destroy_compile (cfg);
+ mono_raise_exception (ex);
+ break;
}
case MONO_EXCEPTION_INVALID_PROGRAM: {
MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
mono_raise_exception (ex);
break;
}
+ case MONO_EXCEPTION_METHOD_ACCESS: {
+ MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
+ mono_destroy_compile (cfg);
+ mono_raise_exception (ex);
+ break;
+ }
+ case MONO_EXCEPTION_FIELD_ACCESS: {
+ MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
+ mono_destroy_compile (cfg);
+ mono_raise_exception (ex);
+ break;
+ }
/* this can only be set if the security manager is active */
case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
- MonoAssembly *assembly = mono_image_get_assembly (method->klass->image);
- MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (target_domain, assembly);
- MonoReflectionMethod *refmet = mono_method_get_object (target_domain, method, NULL);
MonoSecurityManager* secman = mono_security_manager_get_methods ();
MonoObject *exc = NULL;
- gpointer args [3];
+ gpointer args [2];
args [0] = &cfg->exception_data;
- args [1] = refass;
- args [2] = refmet;
+ args [1] = &method;
mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
mono_destroy_compile (cfg);
/* Check if some other thread already did the job. In this case, we can
discard the code this thread generated. */
- if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+ if ((info = lookup_method (target_domain, method))) {
/* We can't use a domain specific method in another domain */
if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
code = info->code_start;
}
if (code == NULL) {
- g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
+ mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
code = cfg->native_code;
+
+ if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method)) {
+ /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
+ mono_domain_register_shared_generic (target_domain,
+ method_get_declaring_generic_method (method), cfg->jit_info);
+ mono_stats.generics_shared_methods++;
+ }
}
mono_destroy_compile (cfg);
mono_domain_lock (target_domain);
- if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+ 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)) {
mono_domain_unlock (target_domain);
return;
mono_domain_lock (domain);
g_hash_table_remove (domain->dynamic_code_hash, method);
- g_hash_table_remove (domain->jit_code_hash, method);
+ mono_internal_hash_table_remove (&domain->jit_code_hash, method);
g_hash_table_remove (domain->jump_trampoline_hash, method);
mono_domain_unlock (domain);
/*
* This needs to be done before freeing code_mp, since the code address is the
- * key in the table, so if we the code_mp first, another thread can grab the
+ * key in the table, so if we free the code_mp first, another thread can grab the
* same code address and replace our entry in the table.
*/
mono_jit_info_table_remove (domain, ji->ji);
if (destroy)
mono_code_manager_destroy (ji->code_mp);
- g_free (ji->ji);
+ mono_thread_hazardous_free_or_queue (ji->ji, g_free);
g_free (ji);
}
mono_domain_lock (target_domain);
- if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+ 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)) {
mono_domain_unlock (target_domain);
return NULL;
}
- method = mono_get_inflated_method (method);
invoke = mono_marshal_get_runtime_invoke (method);
runtime_invoke = mono_jit_compile_method (invoke);
mono_arch_handle_exception (ctx, exc, FALSE);
}
-#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
-
-#ifndef MONO_ARCH_USE_SIGACTION
-#error "Can't use sigaltstack without sigaction"
-#endif
-
-#endif
-
static void
SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
{
+#ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
MonoException *exc = NULL;
+#endif
MonoJitInfo *ji;
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
}
#endif
+ ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
+
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
- /* Can't allocate memory using Boehm GC on altstack */
+ /* we got a stack overflow in the soft-guard pages
+ * There are two cases:
+ * 1) managed code caused the overflow: we unprotect the soft-guard page
+ * and let the arch-specific code trigger the exception handling mechanism
+ * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
+ * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
+ * and hope we can continue with those enabled, at least until the hard-guard page
+ * is hit. The alternative to continuing here is to just print a message and abort.
+ * We may add in the future the code to protect the pages again in the codepath
+ * when we return from unmanaged to managed code.
+ */
+ if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
+ (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
+ mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
+ if (ji) {
+ mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
+ } else {
+ /* We print a message: after this even managed stack overflows
+ * may crash the runtime
+ */
+ fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
+ }
+ return;
+ }
+ /* The hard-guard page has been hit: there is not much we can do anymore
+ * Print a hopefully clear message and abort.
+ */
if (jit_tls->stack_size &&
- ((guint8*)info->si_addr >= (guint8*)jit_tls->end_of_stack - jit_tls->stack_size) &&
- ((guint8*)info->si_addr < (guint8*)jit_tls->end_of_stack))
- exc = mono_domain_get ()->stack_overflow_ex;
- else
- exc = mono_domain_get ()->null_reference_ex;
-#endif
+ ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
+ const char *method;
+ /* we don't do much now, but we can warn the user with a useful message */
+ fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
+ if (ji && ji->method)
+ method = mono_method_full_name (ji->method, TRUE);
+ else
+ method = "Unmanaged";
+ fprintf (stderr, "At %s\n", method);
+ abort ();
+ } else {
+ mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
+ }
+#else
- ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
if (!ji) {
mono_handle_native_sigsegv (SIGSEGV, ctx);
}
mono_arch_handle_exception (ctx, exc, FALSE);
+#endif
}
+#ifndef PLATFORM_WIN32
+
static void
SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
{
mono_print_thread_dump (ctx);
}
+static void
+SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
+{
+ gboolean enabled = mono_trace_is_enabled ();
+
+ mono_trace_enable (!enabled);
+}
+
+#endif
+
static void
SIG_HANDLER_SIGNATURE (sigint_signal_handler)
{
mono_arch_handle_exception (ctx, exc, FALSE);
}
-static void
-SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
-{
- gboolean enabled = mono_trace_is_enabled ();
-
- mono_trace_enable (!enabled);
-}
-
#ifdef PLATFORM_MACOSX
/*
sa.sa_sigaction = handler;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+ if (signo == SIGSEGV)
+ sa.sa_flags |= SA_ONSTACK;
+#endif
#else
sa.sa_handler = handler;
sigemptyset (&sa.sa_mask);
static void
mono_runtime_install_handlers (void)
{
-#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
- struct sigaction sa;
-#endif
-
#ifdef PLATFORM_WIN32
win32_seh_init();
win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
add_signal_handler (SIGABRT, sigabrt_signal_handler);
/* catch SIGSEGV */
-#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
- sa.sa_sigaction = sigsegv_signal_handler;
- sigemptyset (&sa.sa_mask);
- sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
- g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
-#else
add_signal_handler (SIGSEGV, sigsegv_signal_handler);
-#endif
#endif /* PLATFORM_WIN32 */
}
}
#endif
+#ifdef PLATFORM_WIN32
+static HANDLE win32_main_thread;
+static MMRESULT win32_timer;
+
+static void CALLBACK
+win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+ CONTEXT context;
+
+ context.ContextFlags = CONTEXT_CONTROL;
+ if (GetThreadContext (win32_main_thread, &context)) {
+#ifdef _WIN64
+ mono_profiler_stat_hit ((guchar *) context.Rip, &context);
+#else
+ mono_profiler_stat_hit ((guchar *) context.Eip, &context);
+#endif
+ }
+}
+#endif
+
static void
setup_stat_profiler (void)
{
return;
inited = 1;
add_signal_handler (SIGPROF, sigprof_signal_handler);
+#elif defined (PLATFORM_WIN32)
+ static int inited = 0;
+ TIMECAPS timecaps;
+
+ if (inited)
+ return;
+
+ inited = 1;
+ if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
+ return;
+
+ if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
+ return;
+
+ if (timeBeginPeriod (1) != TIMERR_NOERROR)
+ return;
+
+ if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
+ timeEndPeriod (1);
+ return;
+ }
#endif
}
return mono_get_addr_from_ftnptr (addr);
}
+#ifdef MONO_ARCH_HAVE_IMT
+static gpointer
+mini_get_imt_trampoline (void)
+{
+ static gpointer tramp = NULL;
+ if (!tramp)
+ tramp = mono_arch_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
+ return tramp;
+}
+#endif
+
+#ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
+static gpointer
+mini_get_vtable_trampoline (void)
+{
+ static gpointer tramp = NULL;
+ if (!tramp)
+ tramp = mono_arch_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
+ return tramp;
+}
+#endif
+
static void
mini_parse_debug_options (void)
{
InitializeCriticalSection (&jit_mutex);
- global_codeman = mono_code_manager_new ();
+ if (!global_codeman)
+ global_codeman = mono_code_manager_new ();
jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
mono_arch_cpu_init ();
+ mono_arch_init ();
+
mono_init_trampolines ();
mono_init_exceptions ();
domain = mono_init_version (filename, runtime_version);
else
domain = mono_init_from_assembly (filename, filename);
+#ifdef MONO_ARCH_HAVE_IMT
+ mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
+ mono_install_imt_trampoline (mini_get_imt_trampoline ());
+#if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
+ mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
+#endif
+#endif
mono_icall_init ();
mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
g_print ("Locals stack size: %ld\n", mono_jit_stats.locals_stack_size);
g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
+ g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
g_print ("Used classes: %ld\n", mono_stats.used_class_count);
g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
mono_stats.inflated_method_count);
g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
+ g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
+
+ g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
+ g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
+ g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
+
+ g_print ("Dynamic code allocs: %ld\n", mono_stats.dynamic_code_alloc_count);
+ g_print ("Dynamic code bytes: %ld\n", mono_stats.dynamic_code_bytes_count);
+ g_print ("Dynamic code frees: %ld\n", mono_stats.dynamic_code_frees_count);
- if (mono_use_security_manager) {
+ g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
+ g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
+ g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
+ g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
+ g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
+ g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
+ g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
+ g_print ("IMT thunks size: %ld\n", mono_stats.imt_thunks_size);
+
+ g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
+ g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
+ g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
+
+ g_print ("Hazardous pointers: %ld\n", mono_stats.hazardous_pointer_count);
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
g_print ("\nDecl security check : %ld\n", mono_jit_stats.cas_declsec_check);
g_print ("LinkDemand (user) : %ld\n", mono_jit_stats.cas_linkdemand);
g_print ("LinkDemand (icall) : %ld\n", mono_jit_stats.cas_linkdemand_icall);
mono_profiler_shutdown ();
- mono_debug_cleanup ();
-
mono_icall_cleanup ();
mono_runtime_cleanup_handlers ();
mono_domain_free (domain, TRUE);
+ mono_debugger_cleanup ();
+
mono_code_manager_destroy (global_codeman);
g_hash_table_destroy (jit_icall_name_hash);
if (class_init_hash_addr)
g_hash_table_destroy (class_init_hash_addr);
g_free (emul_opcode_map);
+ mono_arch_cleanup ();
+
mono_cleanup ();
mono_trace_cleanup ();
mono_counters_dump (-1, stdout);
+ if (mono_inject_async_exc_method)
+ mono_method_desc_free (mono_inject_async_exc_method);
+
TlsFree(mono_jit_tls_id);
DeleteCriticalSection (&jit_mutex);