#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
+#include <mono/metadata/mono-debug.h>
+#include <mono/metadata/mono-debug-debugger.h>
#include "mini.h"
#include <string.h>
#include <ctype.h>
#include "inssel.h"
-#include "debug.h"
#include "jit-icalls.c"
+#define MONO_IS_COND_BRANCH(op) ((op >= CEE_BEQ && op <= CEE_BLT_UN) || (op >= OP_LBEQ && op <= OP_LBLT_UN) || (op >= OP_FBEQ && op <= OP_FBLT_UN))
+
#define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
+gboolean mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
static gpointer mono_jit_compile_method (MonoMethod *method);
static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
+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);
+
extern guint8 mono_burg_arity [];
/* helper methods signature */
static MonoMethodSignature *helper_sig_long_long_long = NULL;
static MonoMethodSignature *helper_sig_long_long_int = NULL;
static MonoMethodSignature *helper_sig_newarr = NULL;
+static MonoMethodSignature *helper_sig_newarr_specific = NULL;
static MonoMethodSignature *helper_sig_ldstr = NULL;
static MonoMethodSignature *helper_sig_domain_get = NULL;
static MonoMethodSignature *helper_sig_object_new = NULL;
+static MonoMethodSignature *helper_sig_object_new_specific = NULL;
static MonoMethodSignature *helper_sig_compile = NULL;
static MonoMethodSignature *helper_sig_compile_virt = NULL;
static MonoMethodSignature *helper_sig_obj_ptr = NULL;
static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
static MonoMethodSignature *helper_sig_ptr_obj = NULL;
+static MonoMethodSignature *helper_sig_ptr_int = NULL;
static MonoMethodSignature *helper_sig_initobj = NULL;
static MonoMethodSignature *helper_sig_memcpy = NULL;
static MonoMethodSignature *helper_sig_memset = NULL;
static MonoMethodSignature *helper_sig_long_double = NULL;
static MonoMethodSignature *helper_sig_uint_double = NULL;
static MonoMethodSignature *helper_sig_int_double = NULL;
+static MonoMethodSignature *helper_sig_stelem_ref = NULL;
static guint32 default_opt = MONO_OPT_PEEPHOLE;
gboolean mono_jit_trace_calls = FALSE;
gboolean mono_break_on_exc = FALSE;
gboolean mono_compile_aot = FALSE;
-gboolean mono_trace_coverage = FALSE;
-gboolean mono_jit_profile = FALSE;
-MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
-
-CRITICAL_SECTION *metadata_section = NULL;
static int mini_verbose = 0;
#endif
/* debug function */
-static void
+G_GNUC_UNUSED static void
print_method_from_ip (void *ip)
{
MonoJitInfo *ji;
char *method;
+ char *source;
+ MonoDomain *domain = mono_domain_get ();
- ji = mono_jit_info_table_find (mono_domain_get (), ip);
+ ji = mono_jit_info_table_find (domain, ip);
if (!ji) {
g_print ("No method at %p\n", ip);
return;
}
method = mono_method_full_name (ji->method, TRUE);
- g_print ("IP at offset 0x%x of method %s (%p %p)\n", (char*)ip - (char*)ji->code_start, method, ji->code_start, (char*)ji->code_start + ji->code_size);
+ source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
+
+ g_print ("IP %p at offset 0x%x of method %s (%p %p)\n", ip, (char*)ip - (char*)ji->code_start, method, ji->code_start, (char*)ji->code_start + ji->code_size);
+
+ if (source)
+ g_print ("%s\n", source);
+
+ g_free (source);
g_free (method);
}
} while (0)
#define NEW_DOMAINCONST(cfg,dest) do { \
- if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot) { \
+ if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) { \
NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
} else { \
NEW_PCONST (cfg, dest, (cfg)->domain); \
(dest)->klass = (k); \
} while (0)
-static GHashTable *coverage_hash = NULL;
-
-MonoCoverageInfo *
-mono_allocate_coverage_info (MonoMethod *method, int size)
-{
- MonoCoverageInfo *res;
-
- if (!coverage_hash)
- coverage_hash = g_hash_table_new (NULL, NULL);
-
- res = g_malloc0 (sizeof (MonoCoverageInfo) + sizeof (int) * size * 2);
-
- res->entries = size;
-
- g_hash_table_insert (coverage_hash, method, res);
-
- return res;
-}
-
-MonoCoverageInfo *
-mono_get_coverage_info (MonoMethod *method)
-{
- if (!coverage_hash)
- return NULL;
+#define NEW_GROUP(cfg,dest,el1,el2) do { \
+ (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ (dest)->opcode = OP_GROUP; \
+ (dest)->inst_left = (el1); \
+ (dest)->inst_right = (el2); \
+ } while (0)
- return g_hash_table_lookup (coverage_hash, method);
-}
-
#if 0
static gint
compare_bblock (gconstpointer a, gconstpointer b)
clause = &header->clauses [i];
if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->token_or_filter) &&
(offset < (clause->token_or_filter + filter_lengths [i])))
- return (i << 8) | 128 | clause->flags;
+ return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
- return (i << 8) | 64 | clause->flags;
+ if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
+ return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
+ else
+ return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
}
}
for (i = 0; i < header->num_clauses; ++i) {
clause = &header->clauses [i];
if (MONO_OFFSET_IN_CLAUSE (clause, offset))
- return (i << 8) | clause->flags;
+ return ((i + 1) << 8) | clause->flags;
}
return -1;
}
-static MonoBasicBlock *
+static GList*
mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
{
MonoMethod *method = cfg->method;
MonoExceptionClause *clause;
MonoBasicBlock *handler;
int i;
+ GList *res = NULL;
for (i = 0; i < header->num_clauses; ++i) {
clause = &header->clauses [i];
if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
(!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
- if (clause->flags & type) {
+ if (clause->flags == type) {
handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
g_assert (handler);
- return handler;
+ res = g_list_append (res, handler);
}
}
}
- return NULL;
+ return res;
}
goto handle_enum;
}
return CEE_LDOBJ;
+ case MONO_TYPE_TYPEDBYREF:
+ return CEE_LDOBJ;
+ case MONO_TYPE_GENERICINST:
+ if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
+ return CEE_LDOBJ;
+ return CEE_LDIND_REF;
default:
g_error ("unknown type 0x%02x in type_to_ldind", type->type);
}
goto handle_enum;
}
return CEE_STOBJ;
- /* fail right now */
+ case MONO_TYPE_TYPEDBYREF:
+ return CEE_STOBJ;
+ case MONO_TYPE_GENERICINST:
+ if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
+ return CEE_STOBJ;
+ return CEE_STIND_REF;
default:
- g_error ("unknown type %02x in type_to_stind", type->type);
+ g_error ("unknown type 0x%02x in type_to_stind", type->type);
}
return -1;
}
inst->type = STACK_VTYPE;
return;
}
+ case MONO_TYPE_TYPEDBYREF:
+ inst->klass = mono_defaults.typed_reference_class;
+ inst->type = STACK_VTYPE;
+ return;
+ case MONO_TYPE_GENERICINST:
+ if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE) {
+ inst->klass = mono_class_from_mono_type (type);
+ inst->type = STACK_VTYPE;
+ } else {
+ inst->type = STACK_OBJ;
+ }
+ return;
default:
g_error ("unknown type 0x%02x in eval stack type", type->type);
}
{0},
{0, 1, 0, 1, 0, 0, 4, 0},
{0, 0, 1, 0, 0, 0, 0, 0},
- {0, 1, 0, 1, 0, 2, 0, 0},
+ {0, 1, 0, 1, 0, 2, 4, 0},
{0, 0, 0, 0, 1, 0, 0, 0},
{0, 0, 0, 2, 0, 1, 0, 0},
- {0, 4, 0, 0, 0, 0, 3, 0},
+ {0, 4, 0, 4, 0, 0, 3, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
};
return cfg->domainvar;
}
-static void
-realloc_var_info (MonoCompile *cfg, int count)
-{
- gpointer data;
- int num = cfg->varinfo_count;
-
- g_assert (count > num);
-
- cfg->varinfo_count = count;
-
- data = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * cfg->varinfo_count);
- if (num)
- memcpy (data, cfg->varinfo, sizeof (MonoInst*) * num);
- cfg->varinfo = (MonoInst **)data;
-
- data = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar*) * cfg->varinfo_count);
- if (num)
- memcpy (data, cfg->vars, sizeof (MonoMethodVar*) * num);
- cfg->vars = (MonoMethodVar **)data;
-}
-
MonoInst*
mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
{
MonoInst *inst;
int num = cfg->num_varinfo;
- if ((num + 1) >= cfg->varinfo_count)
- realloc_var_info (cfg, cfg->varinfo_count + 16);
+ if ((num + 1) >= cfg->varinfo_count) {
+ cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
+ cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
+ cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);
+ }
+ /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
mono_jit_stats.allocate_var++;
MONO_INST_NEW (cfg, inst, opcode);
}
}
+/*
+ * 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 >= ((MonoMethodNormal *)cfg->method)->header->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;
+}
+
/*
* This function is called to handle items that are left on the evaluation stack
* at basic block boundaries. What happens is that we save the values to local variables
if (!found) {
bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
for (i = 0; i < count; ++i) {
- /*
- * dietmar suggests that we can reuse temps already allocated
- * for this purpouse, if they occupy the same stack slot and if
- * they are of the same type.
- */
+#if 1
+ /* try to reuse temps already allocated for this purpouse, if they occupy the same
+ * stack slot and if they are of the same type. */
+ bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
+#else
bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
+#endif
}
}
}
goto handle_enum;
} else
return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
+ case MONO_TYPE_TYPEDBYREF:
+ return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
default:
- g_error ("unknown type %02x in ret_type_to_call_opcode", type->type);
+ g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
}
return -1;
}
}
}
+/*
+ * Prepare arguments for passing to a function call.
+ * Return a non-zero value if the arguments can't be passed to the given
+ * signature.
+ * The type checks are not yet complete and some conversions may need
+ * casts on 32 or 64 bit architectures.
+ */
+static int
+check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
+{
+ int i, simple_type;
+
+ if (sig->hasthis) {
+ if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
+ return 1;
+ args++;
+ }
+ for (i = 0; i < sig->param_count; ++i) {
+ if (sig->params [i]->byref) {
+ /*
+ * check the result of ldelema is only passed as an argument if the byref
+ * type matches exactly the array element type.
+ * FIXME: if the argument as been saved on the stack as part of the
+ * interface variable code (the value was on the stack at a basic block boundary)
+ * we need to add the check in that case, too.
+ */
+ if (args [i]->opcode == CEE_LDELEMA) {
+ MonoInst *check;
+ MonoClass *exact_class = mono_class_from_mono_type (sig->params [i]);
+ if (!exact_class->valuetype) {
+ MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
+ check->cil_code = args [i]->cil_code;
+ check->klass = exact_class;
+ check->inst_left = args [i]->inst_left;
+ check->type = STACK_OBJ;
+ args [i]->inst_left = check;
+ }
+ }
+ if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
+ return 1;
+ continue;
+ }
+ simple_type = sig->params [i]->type;
+handle_enum:
+ switch (simple_type) {
+ case MONO_TYPE_VOID:
+ return 1;
+ continue;
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
+ return 1;
+ continue;
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
+ return 1;
+ continue;
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_ARRAY:
+ if (args [i]->type != STACK_OBJ)
+ return 1;
+ continue;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ if (args [i]->type != STACK_I8)
+ return 1;
+ continue;
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ if (args [i]->type != STACK_R8)
+ return 1;
+ continue;
+ case MONO_TYPE_VALUETYPE:
+ if (sig->params [i]->data.klass->enumtype) {
+ simple_type = sig->params [i]->data.klass->enum_basetype->type;
+ goto handle_enum;
+ }
+ if (args [i]->type != STACK_VTYPE)
+ return 1;
+ continue;
+ case MONO_TYPE_TYPEDBYREF:
+ if (args [i]->type != STACK_VTYPE)
+ return 1;
+ continue;
+ default:
+ g_error ("unknown type 0x%02x in check_call_signature", simple_type);
+ }
+ }
+ return 0;
+}
+
inline static int
mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object,
const guint8 *ip, gboolean to_end)
MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
{
MonoCallInst *call;
+ MonoInst *arg;
int i;
MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
call->signature = sig;
call = mono_arch_call_opcode (cfg, bblock, call, virtual);
- for (i = 0; i < (sig->param_count + sig->hasthis); ++i) {
- if (call->args [i]) {
- if (to_end)
- mono_add_ins_to_end (bblock, call->args [i]);
- else
- MONO_ADD_INS (bblock, call->args [i]);
- }
+ for (arg = call->out_args; arg;) {
+ MonoInst *narg = arg->next;
+ arg->next = NULL;
+ if (!arg->cil_code)
+ arg->cil_code = ip;
+ if (to_end)
+ mono_add_ins_to_end (bblock, arg);
+ else
+ MONO_ADD_INS (bblock, arg);
+ arg = narg;
}
return call;
}
inline static int
mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
- MonoInst **args, const guint8 *ip, MonoInst *this)
+ MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
{
- MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, method->signature, args, ip, this);
+ MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
- return mono_spill_call (cfg, bblock, call, method->signature, method->string_ctor, ip, FALSE);
+ return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
}
inline static int
mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
{
MonoInst *ins, *temp = NULL, *store, *load;
+ MonoInst *last_arg = NULL;
int i, nargs;
MonoCallInst *call;
nargs = info->sig->param_count + info->sig->hasthis;
- for (i = 1; i < nargs; i++) {
- call->args [i - 1]->next = call->args [i];
- }
+ for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
if (nargs)
- call->args [nargs - 1]->next = store;
+ last_arg->next = store;
if (cfg->prev_ins) {
store->next = cfg->prev_ins->next;
if (nargs)
- cfg->prev_ins->next = call->args [0];
+ cfg->prev_ins->next = call->out_args;
else
cfg->prev_ins->next = store;
} else {
store->next = cfg->cbb->code;
if (nargs)
- cfg->cbb->code = call->args [0];
+ cfg->cbb->code = call->out_args;
else
cfg->cbb->code = store;
}
handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
MonoInst *iargs [3];
int n;
+ guint32 align = 0;
g_assert (klass);
/*
*/
if (native)
- n = mono_class_native_size (klass, NULL);
+ n = mono_class_native_size (klass, &align);
else
- n = mono_class_value_size (klass, NULL);
-
+ n = mono_class_value_size (klass, &align);
+
+ if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
+ MonoInst *inst;
+ MONO_INST_NEW (cfg, inst, OP_MEMCPY);
+ inst->inst_left = dest;
+ inst->inst_right = src;
+ inst->cil_code = ip;
+ inst->unused = n;
+ MONO_ADD_INS (bblock, inst);
+ return;
+ }
iargs [0] = dest;
iargs [1] = src;
NEW_ICONST (cfg, iargs [2], n);
MONO_ADD_INS (bblock, ins);
break;
default:
+ if (n <= sizeof (gpointer) * 5) {
+ ins->opcode = OP_MEMSET;
+ ins->inst_imm = 0;
+ ins->unused = n;
+ MONO_ADD_INS (bblock, ins);
+ break;
+ }
handle_loaded_temps (cfg, bblock, stack_start, sp);
NEW_ICONST (cfg, ins, n);
iargs [0] = dest;
#define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
+static gboolean
+needs_cctor_run (MonoClass *klass, MonoMethod *caller)
+{
+ int i;
+ MonoMethod *method;
+
+ for (i = 0; i < klass->method.count; ++i) {
+ method = klass->methods [i];
+ if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
+ (strcmp (".cctor", method->name) == 0)) {
+ if (caller == method)
+ return FALSE;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
static gboolean
-mono_method_check_inlining (MonoMethod *method)
+mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
{
MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
MonoMethodSignature *signature = method->signature;
+ MonoVTable *vtable;
int i;
- /* fixme: we should inline wrappers */
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- return FALSE;
-
if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
(method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
(method->klass->marshalbyref) ||
!header || header->num_clauses ||
}
}
+ /*
+ * if we can initialize the class of the method right away, we do,
+ * otherwise we don't allow inlining if the class needs initialization,
+ * since it would mean inserting a call to mono_runtime_class_init()
+ * inside the inlined code
+ */
+ if (!(cfg->opt & MONO_OPT_SHARED)) {
+ vtable = mono_class_vtable (cfg->domain, method->klass);
+ if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
+ mono_runtime_class_init (vtable);
+ else if (!vtable->initialized && needs_cctor_run (method->klass, NULL))
+ return FALSE;
+ } else {
+ /*
+ * If we're compiling for shared code
+ * the cctor will need to be run at aot method load time, for example,
+ * or at the end of the compilation of the inlining method.
+ */
+ if (needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
+ return FALSE;
+ }
//if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
/* also consider num_locals? */
return FALSE;
}
+static MonoInst*
+mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
+{
+ int temp, rank;
+ MonoInst *addr;
+ MonoMethodSignature *esig;
+
+ rank = cmethod->signature->param_count - (is_set? 1: 0);
+ /*
+ * FIXME: handle TypeMismatch for set or use the slow path
+ * for that.
+ */
+ if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
+ MonoInst *indexes;
+ NEW_GROUP (cfg, indexes, sp [1], sp [2]);
+ MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
+ addr->inst_left = sp [0];
+ addr->inst_right = indexes;
+ addr->cil_code = ip;
+ addr->type = STACK_MP;
+ addr->klass = cmethod->klass;
+ return addr;
+ }
+ esig = mono_get_element_address_signature (rank);
+ temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
+ NEW_TEMPLOAD (cfg, addr, temp);
+ return addr;
+}
+
static MonoInst*
mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
op = OP_SQRT;
else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8)
op = OP_ABS;
+#if 0
+ /* OP_FREM is not IEEE compatible */
+ else if (strcmp (cmethod->name, "IEEERemainder") == 0)
+ op = OP_FREM;
+#endif
+ else
+ return NULL;
+ } else if (cmethod->klass == mono_defaults.array_class) {
+ if (strcmp (cmethod->name, "get_Rank") == 0)
+ op = OP_ARRAY_RANK;
+ else if (strcmp (cmethod->name, "get_Length") == 0)
+ op = CEE_LDLEN;
else
return NULL;
} else {
if (sp [0]->opcode == OP_ICONST) {
*args++ = sp [0];
} else {
- temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
+ temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
*args++ = temp;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
store->cil_code = sp [0]->cil_code;
}
}
+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)
+{
+ MonoInst *ins, *rvar = NULL;
+ MonoMethodHeader *cheader;
+ MonoBasicBlock *ebblock, *sbblock;
+ int i, costs, new_locals_offset;
+
+ if (cfg->verbose_level > 2)
+ g_print ("INLINE START %p %s\n", cmethod, mono_method_full_name (cmethod, TRUE));
+
+ cheader = ((MonoMethodNormal *)cmethod)->header;
+
+ if (!cmethod->inline_info) {
+ mono_jit_stats.inlineable_methods++;
+ cmethod->inline_info = 1;
+ }
+ /* allocate space to store the return value */
+ if (!MONO_TYPE_IS_VOID (fsig->ret)) {
+ rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
+ }
+
+ /* allocate local variables */
+ 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++;
+ sbblock->real_offset = real_offset;
+
+ ebblock = NEW_BBLOCK (cfg);
+ ebblock->block_num = cfg->num_bblocks++;
+ ebblock->real_offset = real_offset;
+
+ costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
+
+ if (costs >= 0 && costs < 60) {
+ if (cfg->verbose_level > 2)
+ g_print ("INLINE END %s\n", mono_method_full_name (cmethod, TRUE));
+
+ mono_jit_stats.inlined_methods++;
+
+ /* always add some code to avoid block split failures */
+ MONO_INST_NEW (cfg, ins, CEE_NOP);
+ MONO_ADD_INS (bblock, ins);
+ ins->cil_code = ip;
+
+ bblock->next_bb = sbblock;
+ link_bblock (cfg, bblock, sbblock);
+
+ if (rvar) {
+ NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
+ *sp++ = ins;
+ }
+ *last_b = ebblock;
+ return costs + 1;
+ } else {
+ if (cfg->verbose_level > 2)
+ g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
+ }
+ return 0;
+}
+
/*
* Some of these comments may well be out-of-date.
* Design decisions: we do a single pass over the IL code (and we do bblock
#define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
#define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
+#define TYPE_PARAM_TO_TYPE(num) (method->klass->generic_inst->data.generic_inst->type_argv [(num)])
+#define TYPE_PARAM_TO_CLASS(num) (mono_class_from_mono_type (TYPE_PARAM_TO_TYPE ((num))))
+
/* offset from br.s -> br like opcodes */
#define BIG_BRANCH_OFFSET 13
+static int
+get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end)
+{
+ unsigned char *ip = start;
+ unsigned char *target;
+ int i;
+ guint cli_addr;
+ MonoBasicBlock *bblock;
+ const MonoOpcode *opcode;
+
+ while (ip < end) {
+ cli_addr = ip - start;
+ i = mono_opcode_value ((const guint8 **)&ip);
+ opcode = &mono_opcodes [i];
+ switch (opcode->argument) {
+ case MonoInlineNone:
+ ip++;
+ break;
+ case MonoInlineString:
+ case MonoInlineType:
+ case MonoInlineField:
+ case MonoInlineMethod:
+ case MonoInlineTok:
+ case MonoInlineSig:
+ case MonoShortInlineR:
+ case MonoInlineI:
+ ip += 5;
+ break;
+ case MonoInlineVar:
+ ip += 3;
+ break;
+ case MonoShortInlineVar:
+ case MonoShortInlineI:
+ ip += 2;
+ break;
+ case MonoShortInlineBrTarget:
+ target = start + cli_addr + 2 + (signed char)ip [1];
+ GET_BBLOCK (cfg, bbhash, bblock, target);
+ ip += 2;
+ break;
+ case MonoInlineBrTarget:
+ target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
+ GET_BBLOCK (cfg, bbhash, bblock, target);
+ ip += 5;
+ break;
+ case MonoInlineSwitch: {
+ guint32 n = read32 (ip + 1);
+ guint32 j;
+ ip += 5;
+ cli_addr += 5 + 4 * n;
+ target = start + cli_addr;
+ GET_BBLOCK (cfg, bbhash, bblock, target);
+
+ for (j = 0; j < n; ++j) {
+ target = start + cli_addr + (gint32)read32 (ip);
+ GET_BBLOCK (cfg, bbhash, bblock, target);
+ ip += 4;
+ }
+ break;
+ }
+ case MonoInlineR:
+ case MonoInlineI8:
+ ip += 9;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ return 0;
+unverified:
+ return 1;
+}
+
+static MonoClassField *
+get_generic_field_inst (MonoClassField *field, MonoClass *klass, MonoClass **retclass)
+{
+ int i;
+ for (i = 0; i < field->parent->field.count; ++i) {
+ if (field == &field->parent->fields [i]) {
+ *retclass = klass;
+ return &klass->fields [i];
+ }
+ }
+ return NULL;
+}
+
/*
* 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)
+ guint inline_offset, gboolean is_virtual_call)
{
MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
MonoInst *ins, **sp, **stack_start;
int i, n, start_new_bblock, align;
int num_calls = 0, inline_costs = 0;
int *filter_lengths = NULL;
+ int breakpoint_id = 0;
guint real_offset;
image = method->klass->image;
bbhash = g_hash_table_new (g_direct_hash, NULL);
}
+ if (cfg->verbose_level > 2)
+ g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
+
+ if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
+ cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
+
+ dont_inline = g_list_prepend (dont_inline, method);
if (cfg->method == method) {
/* ENTRY BLOCK */
arg_array [i] = cfg->varinfo [i];
if (mono_compile_aot)
- cfg->opt |= MONO_OPT_SAHRED;
+ cfg->opt |= MONO_OPT_SHARED;
if (header->num_clauses) {
int size = sizeof (int) * header->num_clauses;
filter_lengths = alloca (size);
memset (filter_lengths, 0, size);
+
+ cfg->spvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ /* prevent it from being register allocated */
+ cfg->spvar->flags |= MONO_INST_INDIRECT;
}
/* handle exception clauses */
for (i = 0; i < header->num_clauses; ++i) {
tblock->real_offset = clause->try_offset;
GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
tblock->real_offset = clause->handler_offset;
+
+ if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
+ clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+ MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
+ MONO_ADD_INS (tblock, ins);
+ }
+
/*g_print ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
while (p < end) {
g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
tblock->in_scount = 1;
tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
tblock->in_stack [0] = cfg->exvar;
+
if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
GET_BBLOCK (cfg, bbhash, tblock, ip + clause->token_or_filter);
tblock->real_offset = clause->token_or_filter;
tblock->in_scount = 1;
tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
tblock->in_stack [0] = cfg->exvar;
+ MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
+ MONO_ADD_INS (tblock, ins);
}
}
}
ADD_BBLOCK (cfg, bbhash, bblock);
if (cfg->method == method) {
- if (mono_method_has_breakpoint (method, FALSE)) {
+ 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_ADD_INS (bblock, ins);
}
}
- if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SAHRED)))) {
+ if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED)))) {
/* we use a separate basic block for the initialization code */
cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
init_localsbb->real_offset = real_offset;
link_bblock (cfg, start_bblock, bblock);
}
- mono_debug_init_method (cfg, bblock);
+ if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end))
+ goto unverified;
+
+ mono_debug_init_method (cfg, bblock, breakpoint_id);
param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * (sig->hasthis + sig->param_count));
if (sig->hasthis)
zero_r8->inst_p0 = &r8_0;
/* add a check for this != NULL to inlined methods */
- if (cfg->method != method && sig->hasthis) {
+ if (is_virtual_call) {
MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
NEW_ARGLOAD (cfg, ins->inst_left, 0);
ins->cil_code = ip;
}
}
+ if (cfg->coverage_info) {
+ MonoInst *store, *one;
+ guint32 cil_offset = ip - header->code;
+ cfg->coverage_info->data [cil_offset].cil_code = ip;
+
+ /* TODO: Use an increment here */
+ NEW_ICONST (cfg, one, 1);
+ one->cil_code = ip;
+
+ NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
+ ins->cil_code = ip;
+
+ MONO_INST_NEW (cfg, store, CEE_STIND_I);
+ store->cil_code = ip;
+ store->inst_left = ins;
+ store->inst_right = one;
+
+ MONO_ADD_INS (bblock, store);
+ }
+
if (cfg->verbose_level > 3)
g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
token = read32 (ip + 1);
/* FIXME: check the signature matches */
cmethod = mono_get_method (image, token, NULL);
- /*
- * The current magic trampoline can't handle this
- * apparently, so we compile the method right away.
- * Later, we may need to fix the trampoline or use a different one.
- */
- ins->inst_p0 = mono_compile_method (cmethod);
+ ins->inst_p0 = cmethod;
MONO_ADD_INS (bblock, ins);
ip += 5;
start_new_bblock = 1;
case CEE_CALLVIRT: {
MonoInst *addr = NULL;
MonoMethodSignature *fsig = NULL;
- MonoMethodHeader *cheader;
int temp, array_rank = 0;
int virtual = *ip == CEE_CALLVIRT;
if (*ip == CEE_CALLI) {
cmethod = NULL;
- cheader = NULL;
CHECK_STACK (1);
--sp;
addr = *sp;
n = fsig->param_count + fsig->hasthis;
} else {
- cmethod = mono_get_method (image, token, NULL);
- cheader = ((MonoMethodNormal *)cmethod)->header;
+ if (method->wrapper_type != MONO_WRAPPER_NONE) {
+ cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
+ } else {
+ cmethod = mono_get_method (image, token, NULL);
+ }
if (!cmethod->klass->inited)
mono_class_init (cmethod->klass);
}
#endif
} else {
- fsig = cmethod->signature;
+ fsig = mono_method_get_signature (cmethod, image, token);
}
n = fsig->param_count + fsig->hasthis;
sp -= n;
+ if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
+ goto unverified;
+
+ if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL)) {
+ int i;
+ for (i = 0; i < n; ++i) {
+ NEW_ARGSTORE (cfg, ins, i, sp [i]);
+ ins->cil_code = ip;
+ MONO_ADD_INS (bblock, ins);
+ }
+ MONO_INST_NEW (cfg, ins, CEE_JMP);
+ ins->cil_code = ip;
+ ins->inst_p0 = cmethod;
+ MONO_ADD_INS (bblock, ins);
+ start_new_bblock = 1;
+ /* skip CEE_RET as well */
+ ip += 6;
+ ins_flag = 0;
+ break;
+ }
if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
ins->cil_code = ip;
break;
}
- if ((cfg->opt & MONO_OPT_INLINE) &&
- (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
- cmethod && cheader && mono_method_check_inlining (cmethod) &&
- method != cmethod && !g_list_find (dont_inline, cmethod)) {
- MonoInst *rvar = NULL;
- MonoBasicBlock *ebblock, *sbblock;
- int costs, new_locals_offset;
-
- if (cfg->verbose_level > 2)
- g_print ("INLINE START %p %s\n", cmethod, mono_method_full_name (cmethod, TRUE));
+ handle_loaded_temps (cfg, bblock, stack_start, sp);
- if (!cmethod->inline_info) {
- mono_jit_stats.inlineable_methods++;
- cmethod->inline_info = 1;
- }
- /* allocate space to store the return value */
- if (!MONO_TYPE_IS_VOID (fsig->ret))
- rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
-
- /* allocate local variables */
- 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++;
- sbblock->real_offset = real_offset;
-
- ebblock = NEW_BBLOCK (cfg);
- ebblock->block_num = cfg->num_bblocks++;
- ebblock->real_offset = real_offset;
-
- dont_inline = g_list_prepend (dont_inline, method);
- costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset);
- dont_inline = g_list_remove (dont_inline, method);
+ if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
+ (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
+ mono_method_check_inlining (cfg, cmethod) &&
+ !g_list_find (dont_inline, cmethod)) {
+ int costs;
+ MonoBasicBlock *ebblock;
- if (costs >= 0 && costs < 60) {
-
- mono_jit_stats.inlined_methods++;
-
- /* always add some code to avoid block split failures */
- MONO_INST_NEW (cfg, ins, CEE_NOP);
- MONO_ADD_INS (bblock, ins);
- ins->cil_code = ip;
-
+ if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
ip += 5;
real_offset += 5;
- bblock->next_bb = sbblock;
- link_bblock (cfg, bblock, sbblock);
-
GET_BBLOCK (cfg, bbhash, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
- if (rvar) {
- NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
- *sp++ = ins;
- }
- if (sp != stack_start) {
- handle_stack_args (cfg, ebblock, stack_start, sp - stack_start);
- sp = stack_start;
- }
- start_new_bblock = 1;
- if (cfg->verbose_level > 2)
- g_print ("INLINE END %s\n", mono_method_full_name (cmethod, TRUE));
-
- // { static int c = 0; printf ("ICOUNT %d %d %s\n", c++, costs, mono_method_full_name (cmethod, TRUE)); }
+ if (!MONO_TYPE_IS_VOID (fsig->ret))
+ sp++;
+
+ /* indicates start of a new block, and triggers a load of all
+ stack arguments at bb boundarie */
+ bblock = ebblock;
inline_costs += costs;
break;
- } else {
-
- if (cfg->verbose_level > 2)
- g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
-
}
}
inline_costs += 10 * num_calls++;
- handle_loaded_temps (cfg, bblock, stack_start, sp);
/* tail recursion elimination */
if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == cfg->method && ip [5] == CEE_RET) {
}
} else if (array_rank) {
- MonoMethodSignature *esig;
MonoInst *addr;
if (strcmp (cmethod->name, "Set") == 0) { /* array Set */
- esig = mono_get_element_address_signature (fsig->param_count - 1);
-
- temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
- NEW_TEMPLOAD (cfg, addr, temp);
+ 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;
if (ins->opcode == CEE_STOBJ) {
}
} else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
- esig = mono_get_element_address_signature (fsig->param_count);
-
- temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
- NEW_TEMPLOAD (cfg, addr, temp);
+ addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
NEW_INDLOAD (cfg, ins, addr, fsig->ret);
ins->cil_code = ip;
*sp++ = ins;
} else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
- /* implement me */
- esig = mono_get_element_address_signature (fsig->param_count);
-
- temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
- NEW_TEMPLOAD (cfg, *sp, temp);
- sp++;
+ addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
+ *sp++ = addr;
} else {
g_assert_not_reached ();
}
ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
*sp++ = ins;
} else {
- if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, virtual ? sp [0] : NULL)) != -1) {
+ if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
NEW_TEMPLOAD (cfg, *sp, temp);
sp++;
}
case CEE_CONV_I1:
case CEE_CONV_I2:
case CEE_CONV_I4:
- case CEE_CONV_I8:
case CEE_CONV_R4:
case CEE_CONV_R8:
case CEE_CONV_U4:
+ case CEE_CONV_I8:
case CEE_CONV_U8:
case CEE_CONV_OVF_I8:
case CEE_CONV_OVF_U8:
case CEE_CONV_R_UN:
CHECK_STACK (1);
ADD_UNOP (*ip);
- ip++;
+ ip++;
break;
case CEE_CONV_OVF_I4:
case CEE_CONV_OVF_I1:
ip++;
break;
case CEE_CPOBJ:
- g_error ("opcode 0x%02x not handled", *ip);
+ CHECK_STACK (2);
+ token = read32 (ip + 1);
+ if (method->wrapper_type != MONO_WRAPPER_NONE)
+ klass = mono_method_get_wrapper_data (method, token);
+ else
+ klass = mono_class_get (image, token);
+
+ mono_class_init (klass);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+ sp -= 2;
+ if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+ MonoInst *store, *load;
+ MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
+ load->cil_code = ip;
+ load->inst_i0 = sp [1];
+ load->type = ldind_type [CEE_LDIND_REF];
+ load->flags |= ins_flag;
+ MONO_INST_NEW (cfg, store, CEE_STIND_REF);
+ store->cil_code = ip;
+ handle_loaded_temps (cfg, bblock, stack_start, sp);
+ MONO_ADD_INS (bblock, store);
+ store->inst_i0 = sp [0];
+ store->inst_i1 = load;
+ store->flags |= ins_flag;
+ } else {
+ n = mono_class_value_size (klass, NULL);
+ 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->unused = n;
+ MONO_ADD_INS (bblock, copy);
+ } else {
+ MonoInst *iargs [3];
+ iargs [0] = sp [0];
+ iargs [1] = sp [1];
+ NEW_ICONST (cfg, iargs [2], n);
+ iargs [2]->cil_code = ip;
+
+ mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+ }
+ }
+ ins_flag = 0;
+ ip += 5;
break;
case CEE_LDOBJ: {
MonoInst *iargs [3];
klass = mono_method_get_wrapper_data (method, token);
else
klass = mono_class_get (image, token);
+
mono_class_init (klass);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+ if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+ MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
+ ins->cil_code = ip;
+ ins->inst_i0 = sp [0];
+ ins->type = ldind_type [CEE_LDIND_REF];
+ ins->flags |= ins_flag;
+ ins_flag = 0;
+ *sp++ = ins;
+ ip += 5;
+ break;
+ }
n = mono_class_value_size (klass, NULL);
ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
- iargs [1] = *sp;
- NEW_ICONST (cfg, iargs [2], n);
- mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+ 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->unused = n;
+ MONO_ADD_INS (bblock, copy);
+ } else {
+ iargs [1] = *sp;
+ NEW_ICONST (cfg, iargs [2], n);
+ iargs [2]->cil_code = ip;
+
+ mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+ }
NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
++sp;
ip += 5;
+ ins_flag = 0;
inline_costs += 1;
break;
}
CHECK_STACK_OVF (1);
n = read32 (ip + 1);
- if (mono_compile_aot) {
- cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
- }
-
- if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot) {
+ if (method->wrapper_type != MONO_WRAPPER_NONE) {
int temp;
- MonoInst *iargs [3];
- NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
- NEW_IMAGECONST (cfg, iargs [1], image);
- NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
- temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
+ MonoInst *iargs [1];
+
+ NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));
+ temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
NEW_TEMPLOAD (cfg, *sp, temp);
- mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+
} else {
- NEW_PCONST (cfg, ins, NULL);
- ins->cil_code = ip;
- ins->type = STACK_OBJ;
- ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
- *sp = ins;
+
+ if (mono_compile_aot) {
+ cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
+ }
+
+ if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
+ int temp;
+ MonoInst *iargs [3];
+ NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
+ NEW_IMAGECONST (cfg, iargs [1], image);
+ NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
+ temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+ } else {
+ NEW_PCONST (cfg, ins, NULL);
+ ins->cil_code = ip;
+ ins->type = STACK_OBJ;
+ ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+ *sp = ins;
+ }
}
+
sp++;
ip += 5;
break;
case CEE_NEWOBJ: {
MonoInst *iargs [2];
+ MonoMethodSignature *fsig;
int temp;
token = read32 (ip + 1);
cmethod = mono_method_get_wrapper_data (method, token);
} else
cmethod = mono_get_method (image, token, NULL);
+ fsig = mono_method_get_signature (cmethod, image, token);
mono_class_init (cmethod->klass);
- n = cmethod->signature->param_count;
+ n = fsig->param_count;
CHECK_STACK (n);
/* move the args to allow room for 'this' in the first position */
if (cmethod->klass->parent == mono_defaults.array_class) {
NEW_METHODCONST (cfg, *sp, cmethod);
- temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, cmethod->signature, sp, ip, FALSE);
+ temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, fsig, sp, ip, FALSE);
} else if (cmethod->string_ctor) {
/* we simply pass a null pointer */
NEW_PCONST (cfg, *sp, NULL);
/* now call the string ctor */
- temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
+ temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
} else {
if (cmethod->klass->valuetype) {
iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
temp = iargs [0]->inst_c0;
NEW_TEMPLOADA (cfg, *sp, temp);
} else {
- NEW_DOMAINCONST (cfg, iargs [0]);
- NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
+ if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
+ NEW_DOMAINCONST (cfg, iargs [0]);
+ NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
- temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
+ temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
+ } else {
+ MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+ NEW_PCONST (cfg, iargs [0], vtable);
+ if (cmethod->klass->has_finalize || cmethod->klass->marshalbyref || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
+ temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
+ else
+ temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
+ }
NEW_TEMPLOAD (cfg, *sp, temp);
}
- /* now call the actual ctor */
- mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
+ if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
+ mono_method_check_inlining (cfg, cmethod) &&
+ !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
+ !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))) {
+
+ ip += 5;
+ real_offset += 5;
+
+ GET_BBLOCK (cfg, bbhash, bblock, ip);
+ ebblock->next_bb = bblock;
+ link_bblock (cfg, ebblock, bblock);
+
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ sp++;
+
+ /* indicates start of a new block, and triggers a load
+ of all stack arguments at bb boundarie */
+ bblock = ebblock;
+
+ inline_costs += costs;
+ break;
+
+ } else {
+ mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
+ }
+ } else {
+ /* now call the actual ctor */
+ mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
+ }
}
NEW_TEMPLOAD (cfg, *sp, temp);
ip += 5;
*sp++ = ins;
break;
+ case CEE_UNBOX_ANY: {
+ MonoInst *add, *vtoffset;
+ MonoInst *iargs [3];
+
+ CHECK_STACK (1);
+ --sp;
+ token = read32 (ip + 1);
+ if (method->wrapper_type != MONO_WRAPPER_NONE)
+ klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
+ else
+ klass = mono_class_get (image, token);
+ mono_class_init (klass);
+
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+
+ if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+ /* CASTCLASS */
+ MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
+ ins->type = STACK_OBJ;
+ ins->inst_left = *sp;
+ ins->klass = klass;
+ ins->inst_newa_class = klass;
+ ins->cil_code = ip;
+ *sp++ = ins;
+ ip += 5;
+ break;
+ }
+
+ MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
+ ins->type = STACK_OBJ;
+ ins->inst_left = *sp;
+ ins->klass = klass;
+ ins->inst_newa_class = klass;
+ ins->cil_code = ip;
+
+ MONO_INST_NEW (cfg, add, CEE_ADD);
+ NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
+ add->inst_left = ins;
+ add->inst_right = vtoffset;
+ add->type = STACK_MP;
+ *sp = add;
+ ip += 5;
+ /* LDOBJ impl */
+ n = mono_class_value_size (klass, NULL);
+ 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->unused = n;
+ MONO_ADD_INS (bblock, copy);
+ } else {
+ iargs [1] = *sp;
+ NEW_ICONST (cfg, iargs [2], n);
+ iargs [2]->cil_code = ip;
+
+ mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+ }
+ NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
+ ++sp;
+ inline_costs += 2;
+ break;
+ }
case CEE_UNBOX: {
MonoInst *add, *vtoffset;
- /* FIXME: need to check class: move to inssel.brg? */
+
CHECK_STACK (1);
--sp;
token = read32 (ip + 1);
else
klass = mono_class_get (image, token);
mono_class_init (klass);
+
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+
+ MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
+ ins->type = STACK_OBJ;
+ ins->inst_left = *sp;
+ ins->klass = klass;
+ ins->inst_newa_class = klass;
+ ins->cil_code = ip;
+
MONO_INST_NEW (cfg, add, CEE_ADD);
NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
- add->inst_left = *sp;
+ add->inst_left = ins;
add->inst_right = vtoffset;
add->type = STACK_MP;
*sp++ = add;
ip += 5;
- inline_costs += 1;
+ inline_costs += 2;
break;
}
case CEE_CASTCLASS:
--sp;
klass = mono_class_get (image, read32 (ip + 1));
mono_class_init (klass);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
ins->type = STACK_OBJ;
ins->inst_left = *sp;
ins->klass = klass;
case CEE_STFLD: {
MonoInst *offset_ins;
MonoClassField *field;
+ MonoBasicBlock *ebblock;
+ int costs;
guint foffset;
if (*ip == CEE_STFLD) {
// goto unverified;
token = read32 (ip + 1);
field = mono_field_from_token (image, token, &klass);
+ if (field->parent->gen_params)
+ field = get_generic_field_inst (field, method->klass, &klass);
mono_class_init (klass);
+
foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
/* FIXME: mark instructions for use in SSA */
if (*ip == CEE_STFLD) {
if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
- /* fixme: we need to inline that call somehow */
MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
MonoInst *iargs [5];
+
iargs [0] = sp [0];
NEW_CLASSCONST (cfg, iargs [1], klass);
NEW_FIELDCONST (cfg, iargs [2], field);
- NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
+ NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) :
+ field->offset);
iargs [4] = sp [1];
- mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, iargs, ip, NULL);
+
+ if (cfg->opt & MONO_OPT_INLINE) {
+ costs = inline_method (cfg, stfld_wrapper, stfld_wrapper->signature, bblock,
+ iargs, ip, real_offset, dont_inline, &ebblock);
+ g_assert (costs > 0);
+
+ ip += 5;
+ real_offset += 5;
+
+ GET_BBLOCK (cfg, bbhash, bblock, ip);
+ ebblock->next_bb = bblock;
+ link_bblock (cfg, ebblock, bblock);
+
+ /* indicates start of a new block, and triggers a load
+ of all stack arguments at bb boundarie */
+ bblock = ebblock;
+
+ inline_costs += costs;
+ break;
+ } else {
+ mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, stfld_wrapper->signature, iargs, ip, NULL);
+ }
} else {
MonoInst *store;
NEW_ICONST (cfg, offset_ins, foffset);
MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type);
MonoInst *iargs [4];
int temp;
+
iargs [0] = sp [0];
NEW_CLASSCONST (cfg, iargs [1], klass);
NEW_FIELDCONST (cfg, iargs [2], field);
NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
- temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, iargs, ip, NULL);
- if (*ip == CEE_LDFLDA) {
- /* not sure howto handle this */
- NEW_TEMPLOADA (cfg, *sp, temp);
+ if (cfg->opt & MONO_OPT_INLINE) {
+ costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock,
+ iargs, ip, real_offset, dont_inline, &ebblock);
+ g_assert (costs > 0);
+
+ ip += 5;
+ real_offset += 5;
+
+ GET_BBLOCK (cfg, bbhash, bblock, ip);
+ ebblock->next_bb = bblock;
+ link_bblock (cfg, ebblock, bblock);
+
+ temp = iargs [0]->inst_i0->inst_c0;
+
+ if (*ip == CEE_LDFLDA) {
+ /* not sure howto handle this */
+ NEW_TEMPLOADA (cfg, *sp, temp);
+ } else {
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ }
+ sp++;
+
+ /* indicates start of a new block, and triggers a load of
+ all stack arguments at bb boundarie */
+ bblock = ebblock;
+
+ inline_costs += costs;
+ break;
} else {
- NEW_TEMPLOAD (cfg, *sp, temp);
+ temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, ldfld_wrapper->signature, iargs, ip, NULL);
+ if (*ip == CEE_LDFLDA) {
+ /* not sure howto handle this */
+ NEW_TEMPLOADA (cfg, *sp, temp);
+ } else {
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ }
+ sp++;
}
- sp++;
} else {
NEW_ICONST (cfg, offset_ins, foffset);
MONO_INST_NEW (cfg, ins, CEE_ADD);
case CEE_LDSFLDA:
case CEE_STSFLD: {
MonoClassField *field;
- MonoVTable *vtable;
token = read32 (ip + 1);
handle_loaded_temps (cfg, bblock, stack_start, sp);
- if (((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)) {
+ if (((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot)) {
int temp;
MonoInst *iargs [2];
g_assert (field->parent);
temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
NEW_TEMPLOAD (cfg, ins, temp);
} else {
+ gpointer addr;
+ MonoVTable *vtable;
vtable = mono_class_vtable (cfg->domain, klass);
- NEW_PCONST (cfg, ins, (char*)vtable->data + field->offset);
- ins->cil_code = ip;
+ if (!cfg->domain->thread_static_fields || !(addr = g_hash_table_lookup (cfg->domain->thread_static_fields, field))) {
+ if (!vtable->initialized && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && needs_cctor_run (klass, method)) {
+ MonoInst *iargs [1];
+ NEW_PCONST (cfg, iargs [0], vtable);
+ mono_emit_jit_icall (cfg, bblock, mono_runtime_class_init, iargs, ip);
+ if (cfg->verbose_level > 2)
+ g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
+ } else {
+ mono_runtime_class_init (vtable);
+ }
+ addr = (char*)vtable->data + field->offset;
+ NEW_PCONST (cfg, ins, addr);
+ ins->cil_code = ip;
+ } else {
+ /*
+ * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
+ * This could be later optimized to do just a couple of
+ * memory dereferences with constant offsets.
+ */
+ int temp;
+ MonoInst *iargs [1];
+ NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
+ temp = mono_emit_jit_icall (cfg, bblock, mono_threads_get_static_data, iargs, ip);
+ NEW_TEMPLOAD (cfg, ins, temp);
+ }
}
/* FIXME: mark instructions for use in SSA */
} else
MONO_ADD_INS (bblock, store);
} else {
- 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);
- load->cil_code = ip;
- load->inst_left = ins;
- *sp++ = load;
- load->flags |= ins_flag;
- ins_flag = 0;
- /* fixme: dont see the problem why this does not work */
- //cfg->disable_aot = TRUE;
+ gboolean is_const = FALSE;
+ MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+ if (!((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) &&
+ vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
+ gpointer addr = (char*)vtable->data + field->offset;
+ /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
+ is_const = TRUE;
+ switch (field->type->type) {
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_U1:
+ NEW_ICONST (cfg, *sp, *((guint8 *)addr));
+ sp++;
+ break;
+ case MONO_TYPE_I1:
+ NEW_ICONST (cfg, *sp, *((gint8 *)addr));
+ sp++;
+ break;
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_U2:
+ NEW_ICONST (cfg, *sp, *((guint16 *)addr));
+ sp++;
+ break;
+ case MONO_TYPE_I2:
+ NEW_ICONST (cfg, *sp, *((gint16 *)addr));
+ sp++;
+ break;
+ break;
+ case MONO_TYPE_I4:
+ NEW_ICONST (cfg, *sp, *((gint32 *)addr));
+ sp++;
+ break;
+ case MONO_TYPE_U4:
+ NEW_ICONST (cfg, *sp, *((guint32 *)addr));
+ sp++;
+ break;
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_FNPTR:
+ case MONO_TYPE_ARRAY:
+ NEW_PCONST (cfg, *sp, *((gpointer *)addr));
+ type_to_eval_stack_type (field->type, *sp);
+ sp++;
+ break;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ MONO_INST_NEW (cfg, *sp, OP_I8CONST);
+ sp [0]->type = STACK_I8;
+ sp [0]->inst_l = *((gint64 *)addr);
+ sp++;
+ break;
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ case MONO_TYPE_VALUETYPE:
+ default:
+ is_const = FALSE;
+ break;
+ }
+ }
+
+ 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);
+ load->cil_code = ip;
+ load->inst_left = ins;
+ *sp++ = load;
+ load->flags |= ins_flag;
+ ins_flag = 0;
+ /* fixme: dont see the problem why this does not work */
+ //cfg->disable_aot = TRUE;
+ }
}
ip += 5;
break;
else
klass = mono_class_get (image, token);
mono_class_init (klass);
- handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+ n = mono_type_to_stind (&klass->byval_arg);
+ if (n == CEE_STOBJ) {
+ handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
+ } else {
+ /* FIXME: should check item at sp [1] is compatible with the type of the store. */
+ MonoInst *store;
+ MONO_INST_NEW (cfg, store, n);
+ store->cil_code = ip;
+ store->inst_left = sp [0];
+ store->inst_right = sp [1];
+ store->flags |= ins_flag;
+ MONO_ADD_INS (bblock, store);
+ }
+ ins_flag = 0;
ip += 5;
inline_costs += 1;
break;
else
klass = mono_class_get (image, token);
mono_class_init (klass);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+ if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+ *sp = val;
+ ip += 5;
+ break;
+ }
/* much like NEWOBJ */
- NEW_DOMAINCONST (cfg, iargs [0]);
- NEW_CLASSCONST (cfg, iargs [1], klass);
-
- temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
+ if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
+ NEW_DOMAINCONST (cfg, iargs [0]);
+ NEW_CLASSCONST (cfg, iargs [1], klass);
+
+ temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
+ } else {
+ MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+ NEW_PCONST (cfg, iargs [0], vtable);
+ if (1 || klass->has_finalize || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
+ temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
+ else
+ temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
+ }
NEW_TEMPLOAD (cfg, load, temp);
NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
MONO_INST_NEW (cfg, add, CEE_ADD);
token = read32 (ip + 1);
/* allocate the domainvar - becaus this is used in decompose_foreach */
- if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)
+ if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot)
mono_get_domainvar (cfg);
if (method->wrapper_type != MONO_WRAPPER_NONE)
klass = mono_class_get (image, token);
mono_class_init (klass);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
ins->inst_newa_class = klass;
ins->inst_newa_len = *sp;
ins->type = STACK_OBJ;
sp -= 2;
klass = mono_class_get (image, read32 (ip + 1));
mono_class_init (klass);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
NEW_LDELEMA (cfg, ins, sp, klass);
ins->cil_code = ip;
*sp++ = ins;
ip += 5;
break;
+ case CEE_LDELEM: {
+ MonoInst *load;
+ CHECK_STACK (2);
+ sp -= 2;
+ token = read32 (ip + 1);
+ klass = mono_class_get (image, token);
+ mono_class_init (klass);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+ NEW_LDELEMA (cfg, load, sp, klass);
+ load->cil_code = ip;
+ MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
+ ins->cil_code = ip;
+ ins->inst_left = load;
+ *sp++ = ins;
+ type_to_eval_stack_type (&klass->byval_arg, ins);
+ ip += 5;
+ break;
+ }
case CEE_LDELEM_I1:
case CEE_LDELEM_U1:
case CEE_LDELEM_I2:
case CEE_STELEM_I4:
case CEE_STELEM_I8:
case CEE_STELEM_R4:
- case CEE_STELEM_R8:
+ case CEE_STELEM_R8: {
+ MonoInst *load;
+ /*
+ * translate to:
+ * stind.x (ldelema (array, index), val)
+ * ldelema does the bounds check
+ */
+ CHECK_STACK (3);
+ sp -= 3;
+ klass = array_access_to_klass (*ip);
+ NEW_LDELEMA (cfg, load, sp, klass);
+ 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];
+ ++ip;
+ handle_loaded_temps (cfg, bblock, stack_start, sp);
+ MONO_ADD_INS (bblock, ins);
+ inline_costs += 1;
+ cfg->disable_ssa = TRUE;
+ break;
+ }
+ case CEE_STELEM: {
+ MonoInst *load;
+ /*
+ * translate to:
+ * stind.x (ldelema (array, index), val)
+ * ldelema does the bounds check
+ */
+ CHECK_STACK (3);
+ sp -= 3;
+ token = read32 (ip + 1);
+ klass = mono_class_get (image, token);
+ mono_class_init (klass);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+ if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+ 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_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
+ } else {
+ NEW_LDELEMA (cfg, load, sp, klass);
+ load->cil_code = ip;
+ MONO_INST_NEW (cfg, ins, mono_type_to_stind (&klass->byval_arg));
+ ins->cil_code = ip;
+ ins->inst_left = load;
+ ins->inst_right = sp [2];
+ handle_loaded_temps (cfg, bblock, stack_start, sp);
+ MONO_ADD_INS (bblock, ins);
+ }
+ ip += 5;
+ inline_costs += 1;
+ cfg->disable_ssa = TRUE;
+ break;
+ }
case CEE_STELEM_REF: {
- MonoInst *load;
- /*
- * translate to:
- * stind.x (ldelema (array, index), val)
- * ldelema does the bounds check
- */
+ MonoInst *iargs [3];
+
CHECK_STACK (3);
sp -= 3;
- klass = array_access_to_klass (*ip);
- NEW_LDELEMA (cfg, load, sp, klass);
- load->cil_code = ip;
- MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+
+ handle_loaded_temps (cfg, bblock, stack_start, sp);
+
+ iargs [2] = sp [2];
+ iargs [1] = sp [1];
+ iargs [0] = sp [0];
+
+ mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
+
+ /*
+ 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 = load;
+ ins->inst_left = group;
ins->inst_right = sp [2];
- ++ip;
- handle_loaded_temps (cfg, bblock, stack_start, sp);
MONO_ADD_INS (bblock, ins);
- /* FIXME: add the implicit STELEM_REF castclass */
+ */
+
+ ++ip;
inline_costs += 1;
cfg->disable_ssa = TRUE;
break;
handle = mono_ldtoken (image, n, &handle_class);
mono_class_init (handle_class);
- if (((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)) {
+ if (((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot)) {
int temp;
MonoInst *res, *store, *addr, *vtvar, *iargs [2];
start_new_bblock = 1;
break;
case CEE_LEAVE:
- case CEE_LEAVE_S:
+ case CEE_LEAVE_S: {
+ GList *handlers;
if (*ip == CEE_LEAVE) {
target = ip + 5 + (gint32)read32(ip + 1);
} else {
/* fixme: call fault handler ? */
- if ((tblock = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
- link_bblock (cfg, bblock, tblock);
- MONO_INST_NEW (cfg, ins, OP_HANDLER);
- ins->cil_code = ip;
- ins->inst_target_bb = tblock;
- MONO_ADD_INS (bblock, ins);
+ if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
+ GList *tmp;
+ for (tmp = handlers; tmp; tmp = tmp->next) {
+ tblock = tmp->data;
+ link_bblock (cfg, bblock, tblock);
+ MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
+ ins->cil_code = ip;
+ ins->inst_target_bb = tblock;
+ MONO_ADD_INS (bblock, ins);
+ }
+ g_list_free (handlers);
}
-
MONO_INST_NEW (cfg, ins, CEE_BR);
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
else
ip += 2;
-
break;
+ }
case CEE_STIND_I:
CHECK_STACK (2);
MONO_INST_NEW (cfg, ins, *ip);
}
case CEE_PREFIX1: {
switch (ip [1]) {
- case CEE_ARGLIST:
- g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
+ case CEE_ARGLIST: {
+ /* somewhat similar to LDTOKEN */
+ MonoInst *addr, *vtvar;
+ CHECK_STACK_OVF (1);
+ vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL);
+
+ NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
+ addr->cil_code = ip;
+ MONO_INST_NEW (cfg, ins, OP_ARGLIST);
+ ins->cil_code = ip;
+ ins->inst_left = addr;
+ MONO_ADD_INS (bblock, ins);
+ NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
+ ins->cil_code = ip;
+ *sp++ = ins;
+ ip += 2;
break;
+ }
case CEE_CEQ:
case CEE_CGT:
case CEE_CGT_UN:
n = read32 (ip + 2);
if (method->wrapper_type != MONO_WRAPPER_NONE)
cmethod = mono_method_get_wrapper_data (method, n);
- else
+ else {
cmethod = mono_get_method (image, n, NULL);
-
+
+ /*
+ * We can't do this in mono_ldftn, since it is used in
+ * the synchronized wrapper, leading to an infinite loop.
+ */
+ if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ cmethod = mono_marshal_get_synchronized_wrapper (cmethod);
+ }
+
mono_class_init (cmethod->klass);
handle_loaded_temps (cfg, bblock, stack_start, sp);
klass = mono_method_get_wrapper_data (method, token);
else
klass = mono_class_get (image, token);
- handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
+ if (klass->byval_arg.type == MONO_TYPE_VAR)
+ klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+ if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+ MonoInst *store, *load;
+ NEW_PCONST (cfg, load, NULL);
+ load->cil_code = ip;
+ load->type = STACK_OBJ;
+ MONO_INST_NEW (cfg, store, CEE_STIND_REF);
+ store->cil_code = ip;
+ handle_loaded_temps (cfg, bblock, stack_start, sp);
+ MONO_ADD_INS (bblock, store);
+ store->inst_i0 = sp [0];
+ store->inst_i1 = load;
+ break;
+ } else {
+ handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
+ }
ip += 6;
inline_costs += 1;
break;
+ case CEE_CONSTRAINED_:
+ /* FIXME: implement */
+ token = read32 (ip + 2);
+ ip += 6;
+ break;
case CEE_CPBLK:
case CEE_INITBLK: {
MonoInst *iargs [3];
inline_costs += 1;
break;
}
+ case CEE_NO_:
+ if (ip [2] & 0x1)
+ ins_flag |= MONO_INST_NOTYPECHECK;
+ if (ip [2] & 0x2)
+ ins_flag |= MONO_INST_NORANGECHECK;
+ /* we ignore the no-nullcheck for now since we
+ * really do it explicitly only when doing callvirt->call
+ */
+ ip += 3;
+ break;
case CEE_RETHROW: {
MonoInst *load;
/* FIXME: check we are in a catch handler */
case CEE_SIZEOF:
CHECK_STACK_OVF (1);
token = read32 (ip + 2);
+ /* FIXXME: handle generics. */
if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
MonoType *type = mono_type_create_from_typespec (image, token);
token = mono_type_size (type, &align);
case CEE_REFANYTYPE:
g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
break;
+ case CEE_READONLY_:
+ ip += 2;
+ break;
default:
g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
}
g_hash_table_destroy (bbhash);
}
+ dont_inline = g_list_remove (dont_inline, method);
return inline_costs;
inline_failure:
if (cfg->method != method)
g_hash_table_destroy (bbhash);
+ dont_inline = g_list_remove (dont_inline, method);
return -1;
unverified:
g_hash_table_destroy (bbhash);
g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code,
mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
+ dont_inline = g_list_remove (dont_inline, method);
return -1;
}
helper_sig_newarr->params [2] = &mono_defaults.int32_class->byval_arg;
helper_sig_newarr->pinvoke = 1;
+ /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
+ helper_sig_newarr_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
+ helper_sig_newarr_specific->params [0] = &mono_defaults.int_class->byval_arg;
+ helper_sig_newarr_specific->params [1] = &mono_defaults.int32_class->byval_arg;
+ helper_sig_newarr_specific->ret = &mono_defaults.object_class->byval_arg;
+ helper_sig_newarr_specific->pinvoke = 1;
+
/* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
helper_sig_object_new = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
helper_sig_object_new->params [0] = helper_sig_object_new->params [1] = &mono_defaults.int_class->byval_arg;
helper_sig_object_new->ret = &mono_defaults.object_class->byval_arg;
helper_sig_object_new->pinvoke = 1;
+ /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
+ helper_sig_object_new_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+ helper_sig_object_new_specific->params [0] = &mono_defaults.int_class->byval_arg;
+ helper_sig_object_new_specific->ret = &mono_defaults.object_class->byval_arg;
+ helper_sig_object_new_specific->pinvoke = 1;
+
/* void* mono_method_compile (MonoMethod*) */
helper_sig_compile = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
helper_sig_compile->params [0] = helper_sig_compile->ret = &mono_defaults.int_class->byval_arg;
helper_sig_domain_get->ret = &mono_defaults.int_class->byval_arg;
helper_sig_domain_get->pinvoke = 1;
+ /* void* stelem_ref (MonoArray *, int index, MonoObject *) */
+ helper_sig_stelem_ref = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
+ helper_sig_stelem_ref->params [0] = &mono_defaults.array_class->byval_arg;
+ helper_sig_stelem_ref->params [1] = &mono_defaults.int32_class->byval_arg;
+ helper_sig_stelem_ref->params [2] = &mono_defaults.object_class->byval_arg;
+ helper_sig_stelem_ref->ret = &mono_defaults.void_class->byval_arg;
+ helper_sig_stelem_ref->pinvoke = 1;
+
/* long amethod (long, long) */
helper_sig_long_long_long = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
helper_sig_long_long_long->params [0] = helper_sig_long_long_long->params [1] =
helper_sig_ptr_obj->ret = &mono_defaults.int_class->byval_arg;
helper_sig_ptr_obj->pinvoke = 1;
+ /* IntPtr amethod (int) */
+ helper_sig_ptr_int = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+ helper_sig_ptr_int->params [0] = &mono_defaults.int32_class->byval_arg;
+ helper_sig_ptr_int->ret = &mono_defaults.int_class->byval_arg;
+ helper_sig_ptr_int->pinvoke = 1;
+
/* long amethod (long, guint32) */
helper_sig_long_long_int = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
helper_sig_long_long_int->params [0] = &mono_defaults.int64_class->byval_arg;
return g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
}
+gconstpointer
+mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
+{
+ char *name;
+ MonoMethod *wrapper;
+
+ if (callinfo->wrapper)
+ return callinfo->wrapper;
+ name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
+ wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
+ callinfo->wrapper = mono_jit_compile_method (wrapper);
+ g_free (name);
+ return callinfo->wrapper;
+}
+
MonoJitICallInfo *
mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
{
MonoJitICallInfo *info;
- MonoMethod *wrapper;
- char *n;
g_assert (func);
g_assert (name);
info = g_new (MonoJitICallInfo, 1);
- info->name = g_strdup (name);
+ info->name = name;
info->func = func;
info->sig = sig;
) {
info->wrapper = func;
} else {
- g_assert (sig);
- n = g_strdup_printf ("__icall_wrapper_%s", name);
- wrapper = mono_marshal_get_icall_wrapper (sig, n, func);
- info->wrapper = mono_jit_compile_method (wrapper);
- g_free (n);
+ info->wrapper = NULL;
+ mono_icall_get_wrapper (info);
}
- g_hash_table_insert (jit_icall_hash_name, info->name, info);
+ g_hash_table_insert (jit_icall_hash_name, (gpointer)info->name, info);
g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
if (func != info->wrapper)
g_hash_table_insert (jit_icall_hash_addr, (gpointer)info->wrapper, info);
}
void
-mono_register_opcode_emulation (int opcode, MonoMethodSignature *sig, gpointer func)
+mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
{
MonoJitICallInfo *info;
- char *name;
if (!emul_opcode_hash)
emul_opcode_hash = g_hash_table_new (NULL, NULL);
g_assert (!sig->hasthis);
g_assert (sig->param_count < 3);
- name = g_strdup_printf ("__emulate_%s", mono_inst_name (opcode));
-
- info = mono_register_jit_icall (func, name, sig, FALSE);
-
- g_free (name);
+ info = mono_register_jit_icall (func, name, sig, no_throw);
g_hash_table_insert (emul_opcode_hash, (gpointer)opcode, info);
}
decompose_foreach (MonoInst *tree, gpointer data)
{
static MonoJitICallInfo *newarr_info = NULL;
+ static MonoJitICallInfo *newarr_specific_info = NULL;
+ MonoJitICallInfo *info;
switch (tree->opcode) {
case CEE_NEWARR: {
MonoCompile *cfg = data;
MonoInst *iargs [3];
- NEW_DOMAINCONST (cfg, iargs [0]);
- NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
- iargs [2] = tree->inst_newa_len;
-
if (!newarr_info) {
- newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
+ newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
g_assert (newarr_info);
+ newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
+ g_assert (newarr_specific_info);
}
- mono_emulate_opcode (cfg, tree, iargs, newarr_info);
+ if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
+ NEW_DOMAINCONST (cfg, iargs [0]);
+ NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
+ iargs [2] = tree->inst_newa_len;
+
+ info = newarr_info;
+ }
+ else {
+ MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
+
+ NEW_PCONST (cfg, iargs [0], vtable);
+ iargs [1] = tree->inst_newa_len;
+
+ info = newarr_specific_info;
+ }
+
+ mono_emulate_opcode (cfg, tree, iargs, info);
break;
}
mono_mempool_destroy (cfg->mempool);
g_list_free (cfg->ldstr_list);
+ g_free (cfg->varinfo);
+ g_free (cfg->vars);
g_free (cfg);
}
{
MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
- g_free (jit_tls);
+ /* handle_remove should be eventually called for this thread, too
+ g_free (jit_tls);*/
ExitThread (-1);
}
static void
-mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
+setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
{
MonoJitTlsData *jit_tls;
MonoLMF *lmf;
+ MonoThread *thread;
jit_tls = g_new0 (MonoJitTlsData, 1);
TlsSetValue (mono_jit_tls_id, jit_tls);
- jit_tls->abort_func = mono_thread_abort;
+ jit_tls->abort_func = abort_func;
jit_tls->end_of_stack = stack_start;
lmf = g_new0 (MonoLMF, 1);
lmf->ebp = -1;
- jit_tls->lmf = lmf;
+ jit_tls->lmf = jit_tls->first_lmf = lmf;
+
+ thread = mono_thread_current ();
+ if (thread)
+ thread->jit_data = jit_tls;
+}
+
+static void
+mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
+{
+ setup_jit_tls_data (stack_start, mono_thread_abort);
}
void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
static void
mono_thread_attach_cb (guint32 tid, gpointer stack_start)
{
- MonoJitTlsData *jit_tls;
- MonoLMF *lmf;
-
- jit_tls = g_new0 (MonoJitTlsData, 1);
-
- TlsSetValue (mono_jit_tls_id, jit_tls);
-
- jit_tls->abort_func = mono_thread_abort_dummy;
- jit_tls->end_of_stack = stack_start;
+ setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
+}
- lmf = g_new0 (MonoLMF, 1);
- lmf->ebp = -1;
+static void
+mini_thread_cleanup (MonoThread *thread)
+{
+ MonoJitTlsData *jit_tls = thread->jit_data;
- jit_tls->lmf = lmf;
+ if (jit_tls) {
+ g_free (jit_tls->first_lmf);
+ g_free (jit_tls);
+ thread->jit_data = NULL;
+ }
}
void
}
break;
- case 2:
- if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+ case 2:
+ if (tree->opcode == OP_LMUL
+ && (cfg->opt & MONO_OPT_INTRINS)
+ && (tree->inst_left->opcode == CEE_CONV_I8
+ || tree->inst_left->opcode == CEE_CONV_U8)
+ && tree->inst_left->inst_left->type == STACK_I4
+ && (tree->inst_right->opcode == CEE_CONV_I8
+ || tree->inst_right->opcode == CEE_CONV_U8)
+ && tree->inst_right->inst_left->type == STACK_I4) {
+ tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
+ tree->inst_left = tree->inst_left->inst_left;
+ tree->inst_right = tree->inst_right->inst_left;
+ dec_foreach (tree, cfg);
+ } else if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
MonoInst *iargs [2];
iargs [0] = tree->inst_i0;
bb->out_bb = NULL;
bb->next_bb = NULL;
bb->code = bb->last_ins = NULL;
+ bb->cil_code = NULL;
+}
+
+static void
+replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
+{
+ int i;
+
+ for (i = 0; i < bb->out_count; i++) {
+ MonoBasicBlock *ob = bb->out_bb [i];
+ if (ob == orig) {
+ if (!repl) {
+ if (bb->out_count > 1) {
+ bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
+ }
+ bb->out_count--;
+ } else {
+ bb->out_bb [i] = repl;
+ }
+ }
+ }
+}
+
+static void
+replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
+{
+ int i;
+
+ for (i = 0; i < bb->in_count; i++) {
+ MonoBasicBlock *ib = bb->in_bb [i];
+ if (ib == orig) {
+ if (!repl) {
+ if (bb->in_count > 1) {
+ bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
+ }
+ bb->in_count--;
+ } else {
+ bb->in_bb [i] = repl;
+ }
+ }
+ }
}
static void
for (i = 0; i < bb->out_count; i++) {
MonoBasicBlock *ob = bb->out_bb [i];
for (j = 0; j < ob->in_count; j++) {
- if (ob->in_bb [j] == orig)
+ if (ob->in_bb [j] == orig) {
ob->in_bb [j] = repl;
+ }
}
}
}
+
static void
merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
{
static void
optimize_branches (MonoCompile *cfg) {
- int changed = FALSE;
+ int i, changed = FALSE;
MonoBasicBlock *bb, *bbn;
do {
/* we skip the entry block (exit is handled specially instead ) */
for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
+ /* dont touch code inside exception clauses */
+ if (bb->region != -1)
+ continue;
+
+ if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
+ if (cfg->verbose_level > 2)
+ g_print ("nullify block triggered %d\n", bbn->block_num);
+
+ bb->next_bb = bbn->next_bb;
+
+ for (i = 0; i < bbn->out_count; i++)
+ replace_in_block (bbn->out_bb [i], bbn, NULL);
+
+ nullify_basic_block (bbn);
+ changed = TRUE;
+ }
+
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 */
+ if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
+ bb->last_ins->opcode = CEE_BR;
+ bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
+ changed = TRUE;
+ if (cfg->verbose_level > 2)
+ g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
+ }
+
if (bb->region == bbn->region && bb->next_bb == bbn) {
- /* the block are in sequence anyway ... */
+ /* the block are in sequence anyway ... */
- /*
- * miguel: I do not understand what the test below does, could we
- * use a macro, or a comment here? opcode > CEE_BEQ && <= BLT_UN
- *
- * It could also test for bb->last_in only once, and the value
- * could be cached (last_ins->opcode)
- */
- if (bb->last_ins && (bb->last_ins->opcode == CEE_BR || (
- (bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN)))) {
+ /* branches to the following block can be removed */
+ if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
bb->last_ins->opcode = CEE_NOP;
changed = TRUE;
if (cfg->verbose_level > 2)
g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
}
- /* fixme: this causes problems with inlining */
+
if (bbn->in_count == 1) {
if (bbn != cfg->bb_exit) {
//mono_print_bb_code (bb);
}
- } else {
- if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
- bbn = bb->last_ins->inst_target_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
- /*
- if (cfg->verbose_level > 2)
- g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name, bb->block_num, bbn->block_num);
- bb->out_bb [0] = bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
- changed = TRUE;*/
- }
+ }
+ }
+ }
+ } while (changed);
+
+ do {
+ changed = FALSE;
+
+ /* we skip the entry block (exit is handled specially instead ) */
+ for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
+
+ /* dont touch code inside exception clauses */
+ if (bb->region != -1)
+ continue;
+
+ if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
+ if (cfg->verbose_level > 2) {
+ g_print ("nullify block triggered %d\n", bbn->block_num);
+ }
+ bb->next_bb = bbn->next_bb;
+
+ for (i = 0; i < bbn->out_count; i++)
+ replace_in_block (bbn->out_bb [i], bbn, NULL);
+
+ nullify_basic_block (bbn);
+ changed = TRUE;
+ break;
+ }
+
+
+ if (bb->out_count == 1) {
+ bbn = bb->out_bb [0];
+
+ if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
+ bbn = bb->last_ins->inst_target_bb;
+ if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+ bbn->code->inst_target_bb->region == bb->region) {
+
+ if (cfg->verbose_level > 2)
+ g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name,
+ bb->block_num, bbn->block_num);
+
+ replace_basic_block (bb, bb->out_bb [0], bbn->code->inst_target_bb);
+ bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
+ changed = TRUE;
+ break;
}
}
} else if (bb->out_count == 2) {
- /* fixme: this does not correctly unlink the blocks, so we get serious problems in idom code */
- if (0 && bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
+ if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
bbn = bb->last_ins->inst_true_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
- if (cfg->verbose_level > 2)
- g_print ("cbranch to branch triggered %d -> %d (0x%02x)\n", bb->block_num,
- bbn->block_num, bbn->code->opcode);
-
- if (bb->out_bb [0] == bbn) {
- bb->out_bb [0] = bbn->code->inst_target_bb;
- } else if (bb->out_bb [1] == bbn) {
- bb->out_bb [1] = bbn->code->inst_target_bb;
- }
+ if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_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",
+ bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
+ bbn->code->opcode);
+
bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
+
+ replace_in_block (bbn, bb, NULL);
+ if (!bbn->in_count)
+ replace_in_block (bbn->code->inst_target_bb, bbn, bb);
+ replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+
+ link_bblock (cfg, bb, bbn->code->inst_target_bb);
+
+ changed = TRUE;
+ break;
+ }
+
+ bbn = bb->last_ins->inst_false_bb;
+ if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_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",
+ bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
+ bbn->code->opcode);
+
+ bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
+
+ replace_in_block (bbn, bb, NULL);
+ if (!bbn->in_count)
+ replace_in_block (bbn->code->inst_target_bb, bbn, bb);
+ replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+
+ link_bblock (cfg, bb, bbn->code->inst_target_bb);
+
changed = TRUE;
+ break;
}
}
}
}
} while (changed);
+
}
static void
cfg->ret->inst_vtype = sig->ret;
cfg->ret->klass = mono_class_from_mono_type (sig->ret);
}
+ if (cfg->verbose_level > 2)
+ g_print ("creating vars\n");
if (sig->hasthis)
mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
cfg->locals_start = cfg->num_varinfo;
+ 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)
+ g_print ("locals done\n");
}
#if 0
static void
mini_select_instructions (MonoCompile *cfg)
{
+ static int reverse_map [] = {
+ CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
+ CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
+ };
+ static int reverse_fmap [] = {
+ OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
+ OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
+ };
+ static int reverse_lmap [] = {
+ OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
+ OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
+ };
+
MonoBasicBlock *bb;
cfg->state_pool = mono_mempool_new ();
cfg->rs = mono_regstate_new ();
+ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode) &&
+ bb->next_bb != bb->last_ins->inst_false_bb) {
+
+ if (bb->next_bb == bb->last_ins->inst_true_bb) {
+ MonoBasicBlock *tmp = bb->last_ins->inst_true_bb;
+ bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
+ bb->last_ins->inst_false_bb = tmp;
+
+ if (bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
+ bb->last_ins->opcode = reverse_map [bb->last_ins->opcode - CEE_BEQ];
+ } else if (bb->last_ins->opcode >= OP_FBEQ && bb->last_ins->opcode <= OP_FBLT_UN) {
+ bb->last_ins->opcode = reverse_fmap [bb->last_ins->opcode - OP_FBEQ];
+ } else if (bb->last_ins->opcode >= OP_LBEQ && bb->last_ins->opcode <= OP_LBLT_UN) {
+ bb->last_ins->opcode = reverse_lmap [bb->last_ins->opcode - OP_LBEQ];
+ }
+ } else {
+ MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
+ inst->opcode = CEE_BR;
+ inst->inst_target_bb = bb->last_ins->inst_false_bb;
+ mono_bblock_add_inst (bb, inst);
+ }
+ }
+ }
+
#ifdef DEBUG_SELECTION
if (cfg->verbose_level >= 4) {
for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
mono_arch_local_regalloc (cfg, bb);
}
- if (mono_trace_coverage)
- mono_allocate_coverage_info (cfg->method, cfg->num_bblocks);
+ if (cfg->prof_options & MONO_PROFILE_COVERAGE)
+ cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
code = mono_arch_emit_prolog (cfg);
- if (mono_jit_profile)
+ if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
cfg->code_len = code - cfg->native_code;
cfg->epilog_begin = cfg->code_len;
- if (mono_jit_profile)
+ if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
cfg->code_len = code - cfg->native_code;
int dfn = 0, i, code_size_ratio;
mono_jit_stats.methods_compiled++;
+ if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
+ mono_profiler_method_jit (method);
cfg = g_new0 (MonoCompile, 1);
cfg->method = method;
cfg->mempool = mono_mempool_new ();
cfg->opt = opts;
+ cfg->prof_options = mono_profiler_get_events ();
cfg->bb_hash = g_hash_table_new (g_direct_hash, NULL);
cfg->domain = domain;
cfg->verbose_level = mini_verbose;
+ cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX *
+ ((MonoMethodNormal *)method)->header->max_stack);
+
+ if (cfg->verbose_level > 2)
+ g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
/*
* create MonoInst* which represents arguments and local variables
*/
mono_compile_create_vars (cfg);
- if (cfg->verbose_level > 2)
- g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
-
- if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0)) < 0) {
+ if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
+ if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
+ mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
mono_destroy_compile (cfg);
return NULL;
}
mono_jit_stats.basic_blocks += cfg->num_bblocks;
mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
+ if (cfg->num_varinfo > 2000) {
+ /*
+ * we disable some optimizations if there are too many variables
+ * because JIT time may become too expensive. The actual number needs
+ * to be tweaked and eventually the non-linear algorithms should be fixed.
+ */
+ cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
+ cfg->disable_ssa = TRUE;
+ }
/*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
/* Depth-first ordering on basic blocks */
df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
if (cfg->num_bblocks != dfn + 1) {
- if (cfg->verbose_level > 1)
- g_print ("unreachable code?\n");
+ MonoBasicBlock *bb;
+
cfg->num_bblocks = dfn + 1;
+
+ if (!header->clauses) {
+ /* remove unreachable code, because the code in them may be
+ * inconsistent (access to dead variables for example) */
+ for (bb = cfg->bb_entry; bb;) {
+ MonoBasicBlock *bbn = bb->next_bb;
+
+ if (bbn && bbn->region == -1 && !bbn->dfn) {
+ if (cfg->verbose_level > 1)
+ g_print ("found unreachabel code in BB%d\n", bbn->block_num);
+ bb->next_bb = bbn->next_bb;
+ nullify_basic_block (bbn);
+ } else {
+ bb = bb->next_bb;
+ }
+ }
+ }
}
if (cfg->opt & MONO_OPT_LOOP) {
decompose_pass (cfg);
- if (cfg->opt & MONO_OPT_LINEARS) {
+ /* FIXME: disabled with exception clauses: bug #42136 */
+ if ((!header->num_clauses) && (cfg->opt & MONO_OPT_LINEARS)) {
GList *vars, *regs;
/* fixme: maybe we can avoid to compute livenesss here if already computed ? */
cfg->comp_done &= ~MONO_COMP_LIVENESS;
if (!(cfg->comp_done & MONO_COMP_LIVENESS))
mono_analyze_liveness (cfg);
-
+
if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
regs = mono_arch_get_global_int_regs (cfg);
mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
}
//mono_print_code (cfg);
-
- //print_dfn (cfg);
+ //print_dfn (cfg);
+
/* variables are allocated after decompose, since decompose could create temps */
mono_arch_allocate_vars (cfg);
tblock = g_hash_table_lookup (cfg->bb_hash, ip + 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);
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);
g_assert (tblock);
ei->handler_start = cfg->native_code + tblock->native_offset;
-
}
}
}
mono_jit_stats.native_code_size += cfg->code_len;
+ if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
+ mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
+
return cfg;
}
GHashTable *jit_code_hash;
gpointer code;
- if (default_opt & MONO_OPT_SAHRED)
+ if (default_opt & MONO_OPT_SHARED)
target_domain = mono_root_domain;
else
target_domain = domain;
g_hash_table_insert (jit_code_hash, method, code);
+ if (target_domain->jump_target_hash) {
+ MonoJumpInfo patch_info;
+ GSList *list, *tmp;
+ list = g_hash_table_lookup (target_domain->jump_target_hash, method);
+ if (list) {
+ patch_info.next = NULL;
+ patch_info.ip.i = 0;
+ patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
+ patch_info.data.method = method;
+ g_hash_table_remove (target_domain->jump_target_hash, method);
+ }
+ for (tmp = list; tmp; tmp = tmp->next)
+ mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info);
+ g_slist_free (list);
+ }
/* make sure runtime_init is called */
- mono_class_vtable (target_domain, method->klass);
+ mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
return code;
}
mono_arch_handle_exception (ctx, thread->abort_exc, FALSE);
}
+static void
+sigquit_signal_handler (int _dummy)
+{
+ MonoException *exc;
+ GET_CONTEXT
+
+ exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
+
+ mono_arch_handle_exception (ctx, exc, FALSE);
+}
+
+
static void
mono_runtime_install_handlers (void)
{
//g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
+ /* catch SIGQUIT */
+ sa.sa_handler = sigquit_signal_handler;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+ g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);
+
/* catch SIGILL */
sa.sa_handler = sigill_signal_handler;
sigemptyset (&sa.sa_mask);
MonoMethod *nm;
guint8 *addr = NULL;
- if (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class)) {
+ if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
+ (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
nm = mono_marshal_get_remoting_invoke (method);
addr = mono_compile_method (nm);
} else {
mini_init (const char *filename)
{
MonoDomain *domain;
-
+
+ mono_arch_cpu_init ();
+
metadata_section = &ms;
InitializeCriticalSection (metadata_section);
mono_burg_init ();
mono_runtime_install_handlers ();
+ mono_threads_install_cleanup (mini_thread_cleanup);
mono_install_compile_method (mono_jit_compile_method);
mono_install_trampoline (mono_arch_create_jit_trampoline);
* when adding emulation for some opcodes, remember to also add a dummy
* rule to the burg files, because we need the arity information to be correct.
*/
- mono_register_opcode_emulation (OP_LMUL, helper_sig_long_long_long, mono_llmult);
- mono_register_opcode_emulation (OP_LMUL_OVF_UN, helper_sig_long_long_long, mono_llmult_ovf_un);
- mono_register_opcode_emulation (OP_LMUL_OVF, helper_sig_long_long_long, mono_llmult_ovf);
- mono_register_opcode_emulation (OP_LDIV, helper_sig_long_long_long, mono_lldiv);
- mono_register_opcode_emulation (OP_LDIV_UN, helper_sig_long_long_long, mono_lldiv_un);
- mono_register_opcode_emulation (OP_LREM, helper_sig_long_long_long, mono_llrem);
- mono_register_opcode_emulation (OP_LREM_UN, helper_sig_long_long_long, mono_llrem_un);
-
- mono_register_opcode_emulation (OP_LSHL, helper_sig_long_long_int, mono_lshl);
- mono_register_opcode_emulation (OP_LSHR, helper_sig_long_long_int, mono_lshr);
- mono_register_opcode_emulation (OP_LSHR_UN, helper_sig_long_long_int, mono_lshr_un);
-
- mono_register_opcode_emulation (OP_FCONV_TO_U8, helper_sig_ulong_double, mono_fconv_u8);
- mono_register_opcode_emulation (OP_FCONV_TO_U4, helper_sig_uint_double, mono_fconv_u4);
- mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, helper_sig_long_double, mono_fconv_ovf_i8);
- mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, helper_sig_ulong_double, mono_fconv_ovf_u8);
+ mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
+ mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
+ mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
+ mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
+ mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
+ mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
+ mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
+
+ mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
+ mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
+ mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
+
+ mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, TRUE);
+ mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, TRUE);
#if SIZEOF_VOID_P == 4
- mono_register_opcode_emulation (OP_FCONV_TO_U, helper_sig_uint_double, mono_fconv_u4);
+ mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
#else
#warning "fixme: add opcode emulation"
#endif
mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address",
helper_sig_ptr_ptr_ptr, FALSE);
mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
+ mono_register_jit_icall (mono_threads_get_static_data, "mono_threads_get_static_data", helper_sig_ptr_int, FALSE);
mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
+ mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
+ mono_register_jit_icall (mono_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
+ mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", helper_sig_object_new_specific, FALSE);
mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
+ mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
mono_register_jit_icall (mono_string_from_utf16, "mono_string_from_utf16", helper_sig_obj_ptr, FALSE);
mono_register_jit_icall (mono_string_new_wrapper, "mono_string_new_wrapper", helper_sig_obj_ptr, FALSE);
mono_register_jit_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", helper_sig_void_ptr_ptr_ptr, FALSE);
mono_register_jit_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", helper_sig_void_ptr_ptr_ptr, FALSE);
mono_register_jit_icall (g_free, "g_free", helper_sig_void_ptr, FALSE);
+ mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
- mono_runtime_init (domain, mono_thread_start_cb,
- mono_thread_attach_cb);
+ mono_runtime_install_cleanup ((MonoDomainFunc)mini_cleanup);
+ mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
//mono_thread_attach (domain);
return domain;
mini_cleanup (MonoDomain *domain)
{
/*
- * mono_runtime_cleanup() needs to be called early since
- * it needs the execution engine still fully working (it will
- * wait for other threads to finish).
+ * mono_runtime_cleanup() and mono_domain_finalize () need to
+ * be called early since they need the execution engine still
+ * fully working (mono_domain_finalize may invoke managed finalizers
+ * and mono_runtime_cleanup will wait for other threads to finish).
*/
- mono_runtime_cleanup (domain);
-
mono_domain_finalize (domain);
+ mono_runtime_cleanup (domain);
+
mono_profiler_shutdown ();
mono_debug_cleanup ();
+
#ifdef PLATFORM_WIN32
win32_seh_cleanup();
#endif
}
void
-mini_set_defaults (int verbose_level, guint32 opts)
+mono_set_defaults (int verbose_level, guint32 opts)
{
mini_verbose = verbose_level;
default_opt = opts;