#include <config.h>
#include <signal.h>
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <math.h>
+#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
+
+#ifdef PLATFORM_MACOSX
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/exception.h>
+#include <mach/task.h>
+#include <pthread.h>
+#endif
+
+#ifdef PLATFORM_WIN32
+#define _WIN32_WINNT 0x0500
+#endif
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
#define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
-#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == CEE_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
+#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == OP_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
#define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
static gpointer mono_jit_compile_method (MonoMethod *method);
static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
static gpointer mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method);
+inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
return res;
}
+/**
+ * mono_pmip:
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip. This routine is typically invoked from
+ * a debugger like this:
+ *
+ * (gdb) print mono_pmip ($pc)
+ *
+ * Returns: the name of the method at address @ip.
+ */
G_GNUC_UNUSED char *
mono_pmip (void *ip)
{
return get_method_from_ip (ip);
}
-/* debug function */
+/**
+ * mono_print_method_from_ip
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip.
+ *
+ * This prints the name of the method at address @ip in the standard
+ * output. Unlike mono_pmip which returns a string, this routine
+ * prints the value on the standard output.
+ */
void
mono_print_method_from_ip (void *ip)
{
* block_num: unique ID assigned at bblock creation
*/
#define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
-#define ADD_BBLOCK(cfg,bbhash,b) do { \
- g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
+#define ADD_BBLOCK(cfg,b) do { \
+ cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b); \
(b)->block_num = cfg->num_bblocks++; \
(b)->real_offset = real_offset; \
} while (0)
-#define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
- (tblock) = g_hash_table_lookup (bbhash, (ip)); \
+#define GET_BBLOCK(cfg,tblock,ip) do { \
+ (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
if (!(tblock)) { \
if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
(tblock) = NEW_BBLOCK (cfg); \
(tblock)->cil_code = (ip); \
- ADD_BBLOCK (cfg, (bbhash), (tblock)); \
+ ADD_BBLOCK (cfg, (tblock)); \
} \
} while (0)
ins->inst_i0 = cmp; \
MONO_ADD_INS (bblock, ins); \
ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
- GET_BBLOCK (cfg, bbhash, tblock, target); \
+ GET_BBLOCK (cfg, tblock, target); \
link_bblock (cfg, bblock, tblock); \
ins->inst_true_bb = tblock; \
CHECK_BBLOCK (target, ip, tblock); \
ins->inst_false_bb = (next_block); \
start_new_bblock = 1; \
} else { \
- GET_BBLOCK (cfg, bbhash, tblock, ip); \
+ GET_BBLOCK (cfg, tblock, ip); \
link_bblock (cfg, bblock, tblock); \
ins->inst_false_bb = tblock; \
start_new_bblock = 2; \
ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
MONO_ADD_INS (bblock, ins); \
ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
- GET_BBLOCK (cfg, bbhash, tblock, target); \
+ GET_BBLOCK (cfg, tblock, target); \
link_bblock (cfg, bblock, tblock); \
ins->inst_true_bb = tblock; \
CHECK_BBLOCK (target, ip, tblock); \
- GET_BBLOCK (cfg, bbhash, tblock, ip); \
+ GET_BBLOCK (cfg, tblock, ip); \
link_bblock (cfg, bblock, tblock); \
ins->inst_false_bb = tblock; \
start_new_bblock = 2; \
return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
- if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
+ if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
- else
+ else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
+ return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
+ else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
}
}
if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
(!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
if (clause->flags == type) {
- handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
+ handler = cfg->cil_offset_to_bb [clause->handler_offset];
g_assert (handler);
res = g_list_append (res, handler);
}
}
}
-typedef struct {
- const guchar *code;
- MonoBasicBlock *best;
-} PrevStruct;
-
-static void
-previous_foreach (gconstpointer key, gpointer val, gpointer data)
+static MonoBasicBlock*
+find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
{
- PrevStruct *p = data;
- MonoBasicBlock *bb = val;
- //printf ("FIDPREV %d %p %p %p %p %p %d %d %d\n", bb->block_num, p->code, bb, p->best, bb->cil_code, p->best->cil_code,
- //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
-
- if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
- p->best = bb;
-}
+ MonoBasicBlock *best = start;
+ int i;
-static MonoBasicBlock*
-find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
- PrevStruct p;
+ for (i = 0; i < n_bblocks; ++i) {
+ if (bblocks [i]) {
+ MonoBasicBlock *bb = bblocks [i];
- p.code = code;
- p.best = start;
+ if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
+ best = bb;
+ }
+ }
- g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
- return p.best;
+ return best;
}
static void
return opcode;
}
+#ifdef MONO_ARCH_SOFT_FLOAT
+static int
+condbr_to_fp_br (int opcode)
+{
+ switch (opcode) {
+ case CEE_BEQ: return OP_FBEQ;
+ case CEE_BGE: return OP_FBGE;
+ case CEE_BGT: return OP_FBGT;
+ case CEE_BLE: return OP_FBLE;
+ case CEE_BLT: return OP_FBLT;
+ case CEE_BNE_UN: return OP_FBNE_UN;
+ case CEE_BGE_UN: return OP_FBGE_UN;
+ case CEE_BGT_UN: return OP_FBGT_UN;
+ case CEE_BLE_UN: return OP_FBLE_UN;
+ case CEE_BLT_UN: return OP_FBLT_UN;
+ }
+ g_assert_not_reached ();
+ return 0;
+}
+#endif
+
/*
* Returns the type used in the eval stack when @type is loaded.
* FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
/* handles from CEE_CEQ to CEE_CLT_UN */
static const guint16
ceqops_op_map [STACK_MAX] = {
- 0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, OP_LCEQ-CEE_CEQ
+ 0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
};
/*
ins->opcode = OP_LCOMPARE;
return;
case OP_CEQ:
+ ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+ ins->opcode += ceqops_op_map [ins->inst_i0->type];
+ return;
+
case OP_CGT:
case OP_CGT_UN:
case OP_CLT:
case OP_CLT_UN:
- ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+ ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
ins->opcode += ceqops_op_map [ins->inst_i0->type];
return;
/* unops */
ins->type = STACK_PTR;
switch (ins->inst_i0->type) {
case STACK_I4:
+ break;
case STACK_PTR:
case STACK_MP:
+#if SIZEOF_VOID_P == 8
+ ins->opcode = OP_LCONV_TO_U;
+#endif
break;
case STACK_I8:
ins->opcode = OP_LCONV_TO_U;
ins->type = STACK_R8;
ins->opcode += unops_op_map [ins->inst_i0->type];
return;
- case CEE_CKFINITE:
+ case OP_CKFINITE:
ins->type = STACK_R8;
return;
case CEE_CONV_U2:
MONO_INIT_VARINFO (cfg->vars [num], num);
cfg->num_varinfo++;
- //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
+ if (cfg->verbose_level > 2)
+ g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
return inst;
}
case STACK_R8: return &mono_defaults.double_class->byval_arg;
case STACK_MP:
/*
- * FIXME: This doesn't work because mono_class_from_mono_type ()
- * returns the original klass for a byref type, not a 'byref' class,
- * causing the JIT to create variables with the wrong type, for
- * example.
+ * this if used to be commented without any specific reason, but
+ * it breaks #80235 when commented
*/
- /*
if (ins->klass)
return &ins->klass->this_arg;
else
- */
return &mono_defaults.object_class->this_arg;
- case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
+ case STACK_OBJ:
+ /* ins->klass may not be set for ldnull.
+ * Also, if we have a boxed valuetype, we want an object lass,
+ * not the valuetype class
+ */
+ if (ins->klass && !ins->klass->valuetype)
+ return &ins->klass->byval_arg;
+ return &mono_defaults.object_class->byval_arg;
case STACK_VTYPE: return &ins->klass->byval_arg;
default:
g_error ("stack type %d to montype not handled\n", ins->type);
}
static MonoClass*
-array_access_to_klass (int opcode)
+array_access_to_klass (int opcode, MonoInst *array_obj)
{
switch (opcode) {
case CEE_LDELEM_U1:
case CEE_STELEM_R8:
return mono_defaults.double_class;
case CEE_LDELEM_REF:
- case CEE_STELEM_REF:
+ case CEE_STELEM_REF: {
+ MonoClass *klass = array_obj->klass;
+ /* FIXME: add assert */
+ if (klass && klass->rank)
+ return klass->element_class;
return mono_defaults.object_class;
+ }
default:
g_assert_not_reached ();
}
case CEE_BGT_UN:
case CEE_BLE_UN:
case CEE_BLT_UN:
- case CEE_BR:
+ case OP_BR:
case CEE_SWITCH:
prev = bb->code;
while (prev->next && prev->next != bb->last_ins)
}
}
-/*
- * We try to share variables when possible
- */
-static MonoInst *
-mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
-{
- MonoInst *res;
- int pos, vnum;
-
- /* inlining can result in deeper stacks */
- if (slot >= mono_method_get_header (cfg->method)->max_stack)
- return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
-
- pos = ins->type - 1 + slot * STACK_MAX;
-
- switch (ins->type) {
- case STACK_I4:
- case STACK_I8:
- case STACK_R8:
- case STACK_PTR:
- case STACK_MP:
- case STACK_OBJ:
- if ((vnum = cfg->intvars [pos]))
- return cfg->varinfo [vnum];
- res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
- cfg->intvars [pos] = res->inst_c0;
- break;
- default:
- res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
- }
- return res;
-}
-
/*
* merge_stacks:
*
* in the inlined methods do not inherit their in_stack from
* the bblock they are inlined to. See bug #58863 for an
* example.
+ * This hack is disabled since it also prevents proper tracking of types.
*/
+#if 1
+ bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
+#else
if (cfg->inlined_method)
bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
else
bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
+#endif
}
}
}
cfg->patch_info = ji;
}
+static void
+mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
+{
+ if (cfg->compile_aot) {
+ MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
+ jump_info_token->image = image;
+ jump_info_token->token = token;
+ g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
+ }
+}
+
/*
* When we add a tree of instructions, we need to ensure the instructions currently
* on the stack are executed before (like, if we load a value from a local).
if (arg->type != STACK_I4 && arg->type != STACK_PTR)
return 1;
return 0;
- case MONO_TYPE_CLASS:
- case MONO_TYPE_STRING:
case MONO_TYPE_OBJECT:
+ if (arg->type != STACK_OBJ)
+ return 1;
+ return 0;
+ case MONO_TYPE_STRING:
+ if (arg->type != STACK_OBJ)
+ return 1;
+ /* ldnull has arg->klass unset */
+ /*if (arg->klass && arg->klass != mono_defaults.string_class) {
+ G_BREAKPOINT ();
+ return 1;
+ }*/
+ return 0;
+ case MONO_TYPE_CLASS:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
if (arg->type != STACK_OBJ)
return 0;
case MONO_TYPE_GENERICINST:
if (mono_type_generic_inst_is_valuetype (simple_type)) {
+ klass = mono_class_from_mono_type (simple_type);
+ if (klass->enumtype)
+ return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
if (arg->type != STACK_VTYPE)
return 1;
- klass = mono_class_from_mono_type (simple_type);
if (klass != arg->klass)
return 1;
return 0;
MonoInst *arg;
MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
-
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+ /* we need to convert the r4 value to an int value */
+ {
+ int i;
+ for (i = 0; i < sig->param_count; ++i) {
+ if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
+ MonoInst *iargs [1];
+ int temp;
+ iargs [0] = args [i + sig->hasthis];
+
+ temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
+ NEW_TEMPLOAD (cfg, arg, temp);
+ args [i + sig->hasthis] = arg;
+ }
+ }
+ }
+#endif
+
call->inst.cil_code = ip;
call->args = args;
call->signature = sig;
call = mono_arch_call_opcode (cfg, bblock, call, virtual);
type_to_eval_stack_type (sig->ret, &call->inst);
-
+
for (arg = call->out_args; arg;) {
MonoInst *narg = arg->next;
arg->next = NULL;
}
static MonoMethodSignature *
-mono_get_element_address_signature (int arity)
+mono_get_array_new_va_signature (int arity)
{
static GHashTable *sighash = NULL;
MonoMethodSignature *res;
sighash = g_hash_table_new (NULL, NULL);
}
else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
- LeaveCriticalSection (&jit_mutex);
+ mono_jit_unlock ();
return res;
}
/* Only set this only some archs since not all backends can handle varargs+pinvoke */
res->call_convention = MONO_CALL_VARARG;
#endif
- res->params [0] = &mono_defaults.array_class->byval_arg;
#ifdef PLATFORM_WIN32
- /*
- * The default pinvoke calling convention is STDCALL but we need CDECL.
- */
res->call_convention = MONO_CALL_C;
#endif
- for (i = 1; i <= arity; i++)
- res->params [i] = &mono_defaults.int_class->byval_arg;
+ res->params [0] = &mono_defaults.int_class->byval_arg;
+ for (i = 0; i < arity; i++)
+ res->params [i + 1] = &mono_defaults.int_class->byval_arg;
res->ret = &mono_defaults.int_class->byval_arg;
return res;
}
-static MonoMethodSignature *
-mono_get_array_new_va_signature (int arity)
+#ifdef MONO_ARCH_SOFT_FLOAT
+static void
+handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
{
- static GHashTable *sighash = NULL;
- MonoMethodSignature *res;
- int i;
+ MonoInst *iargs [2];
+ iargs [0] = val;
+ iargs [1] = ptr;
- mono_jit_lock ();
- if (!sighash) {
- sighash = g_hash_table_new (NULL, NULL);
- }
- else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
- mono_jit_unlock ();
- return res;
- }
+ mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
+}
- res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
+static int
+handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
+{
+ MonoInst *iargs [1];
+ iargs [0] = ptr;
- res->pinvoke = 1;
-#ifdef MONO_ARCH_VARARG_ICALLS
- /* Only set this only some archs since not all backends can handle varargs+pinvoke */
- res->call_convention = MONO_CALL_VARARG;
-#endif
+ return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
+}
-#ifdef PLATFORM_WIN32
- res->call_convention = MONO_CALL_C;
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+ if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) { \
+ int temp; \
+ NEW_LOCLOADA (cfg, (ins), (idx)); \
+ temp = handle_load_float (cfg, bblock, (ins), (ip)); \
+ NEW_TEMPLOAD (cfg, (ins), temp); \
+ } \
+ } while (0)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+ if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) { \
+ int temp; \
+ NEW_LOCLOADA (cfg, (ins), (idx)); \
+ handle_store_float (cfg, bblock, (ins), *sp, (ip)); \
+ MONO_INST_NEW (cfg, (ins), OP_NOP); \
+ } \
+ } while (0)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+ if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
+ int temp; \
+ NEW_ARGLOADA (cfg, (ins), (idx)); \
+ temp = handle_load_float (cfg, bblock, (ins), (ip)); \
+ NEW_TEMPLOAD (cfg, (ins), temp); \
+ } \
+ } while (0)
+#define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+ if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
+ int temp; \
+ NEW_ARGLOADA (cfg, (ins), (idx)); \
+ handle_store_float (cfg, bblock, (ins), *sp, (ip)); \
+ MONO_INST_NEW (cfg, (ins), OP_NOP); \
+ } \
+ } while (0)
+#else
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
+#define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
#endif
- res->params [0] = &mono_defaults.int_class->byval_arg;
- for (i = 0; i < arity; i++)
- res->params [i + 1] = &mono_defaults.int_class->byval_arg;
-
- res->ret = &mono_defaults.int_class->byval_arg;
-
- g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
- mono_jit_unlock ();
-
- return res;
-}
-
static MonoMethod*
get_memcpy_method (void)
{
vstore->inst_left = add;
vstore->inst_right = val;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (vstore->opcode == CEE_STIND_R4) {
+ handle_store_float (cfg, bblock, add, val, ip);
+ } else
+#endif
if (vstore->opcode == CEE_STOBJ) {
handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
} else
MONO_TYPE_ISSTRUCT (signature->ret))
return FALSE;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ /* this complicates things, fix later */
+ if (signature->ret->type == MONO_TYPE_R4)
+ return FALSE;
+#endif
/* its not worth to inline methods with valuetype arguments?? */
for (i = 0; i < signature->param_count; i++) {
if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
return FALSE;
}
+#ifdef MONO_ARCH_SOFT_FLOAT
+ /* this complicates things, fix later */
+ if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
+ return FALSE;
+#endif
}
/*
{
int temp, rank;
MonoInst *addr;
- MonoMethodSignature *esig;
- char icall_name [256];
- char *name;
- MonoJitICallInfo *info;
+ MonoMethod *addr_method;
+ int element_size;
rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
#endif
}
- /* Need to register the icall so it gets an icall wrapper */
- sprintf (icall_name, "ves_array_element_address_%d", rank);
-
- mono_jit_lock ();
- info = mono_find_jit_icall_by_name (icall_name);
- if (info == NULL) {
- esig = mono_get_element_address_signature (rank);
- name = g_strdup (icall_name);
- info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
-
- g_hash_table_insert (jit_icall_name_hash, name, name);
- }
- mono_jit_unlock ();
-
- /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
- temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
- cfg->flags |= MONO_CFG_HAS_VARARGS;
-
+ element_size = mono_class_array_element_size (cmethod->klass->element_class);
+ addr_method = mono_marshal_get_array_address (rank, element_size);
+ temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
NEW_TEMPLOAD (cfg, addr, temp);
return addr;
+
}
-MonoJitICallInfo **emul_opcode_map = NULL;
+static MonoJitICallInfo **emul_opcode_map = NULL;
MonoJitICallInfo *
mono_find_jit_opcode_emulation (int opcode)
{
+ g_assert (opcode >= 0 && opcode <= OP_LAST);
if (emul_opcode_map)
return emul_opcode_map [opcode];
else
return NULL;
}
+static int
+is_signed_regsize_type (MonoType *type)
+{
+ switch (type->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_I4:
+#if SIZEOF_VOID_P == 8
+ /*case MONO_TYPE_I8: this requires different opcodes in inssel.brg */
+#endif
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
static MonoInst*
mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
return ins;
#endif
} else if (strcmp (cmethod->name, ".ctor") == 0) {
- MONO_INST_NEW (cfg, ins, CEE_NOP);
+ MONO_INST_NEW (cfg, ins, OP_NOP);
return ins;
} else
return NULL;
store->inst_left = args [2];
store->inst_right = load;
return store;
+ } else if (cmethod->klass == mono_defaults.math_class) {
+ if (strcmp (cmethod->name, "Min") == 0) {
+ if (is_signed_regsize_type (fsig->params [0])) {
+ MONO_INST_NEW (cfg, ins, OP_MIN);
+ ins->inst_i0 = args [0];
+ ins->inst_i1 = args [1];
+ return ins;
+ }
+ } else if (strcmp (cmethod->name, "Max") == 0) {
+ if (is_signed_regsize_type (fsig->params [0])) {
+ MONO_INST_NEW (cfg, ins, OP_MAX);
+ ins->inst_i0 = args [0];
+ ins->inst_i1 = args [1];
+ return ins;
+ }
+ }
+ } else if (cmethod->klass->image == mono_defaults.corlib) {
+ if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
+ && strcmp (cmethod->klass->name, "Debugger") == 0) {
+ MONO_INST_NEW (cfg, ins, OP_BREAK);
+ return ins;
+ }
+ if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
+ && strcmp (cmethod->klass->name, "Environment") == 0) {
+#ifdef PLATFORM_WIN32
+ NEW_ICONST (cfg, ins, 1);
+#else
+ NEW_ICONST (cfg, ins, 0);
+#endif
+ return ins;
+ }
}
return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
MonoBasicBlock *ebblock, *sbblock;
int i, costs, new_locals_offset;
MonoMethod *prev_inlined_method;
+ MonoBasicBlock **prev_cil_offset_to_bb;
+ unsigned char* prev_cil_start;
+ guint32 prev_cil_offset_to_bb_len;
+
#if (MONO_INLINE_CALLED_LIMITED_METHODS)
if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
return 0;
prev_inlined_method = cfg->inlined_method;
cfg->inlined_method = cmethod;
+ prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
+ prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
+ prev_cil_start = cfg->cil_start;
costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
cfg->inlined_method = prev_inlined_method;
+ cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
+ cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
+ cfg->cil_start = prev_cil_start;
if ((costs >= 0 && costs < 60) || inline_allways) {
if (cfg->verbose_level > 2)
mono_jit_stats.inlined_methods++;
/* always add some code to avoid block split failures */
- MONO_INST_NEW (cfg, ins, CEE_NOP);
+ MONO_INST_NEW (cfg, ins, OP_NOP);
MONO_ADD_INS (bblock, ins);
ins->cil_code = ip;
* or through repeated runs where the compiler applies offline the optimizations to
* each method and then decides if it was worth it.
*
- * TODO:
- * * consider using an array instead of an hash table (bb_hash)
*/
#define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
#define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
#define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
#define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
+#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
/* offset from br.s -> br like opcodes */
#define BIG_BRANCH_OFFSET 13
-static gboolean
+static inline gboolean
ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
{
- MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
+ MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
return b == NULL || b == bb;
}
static int
-get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
+get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
{
unsigned char *ip = start;
unsigned char *target;
break;
case MonoShortInlineBrTarget:
target = start + cli_addr + 2 + (signed char)ip [1];
- GET_BBLOCK (cfg, bbhash, bblock, target);
+ GET_BBLOCK (cfg, bblock, target);
ip += 2;
if (ip < end)
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
break;
case MonoInlineBrTarget:
target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
- GET_BBLOCK (cfg, bbhash, bblock, target);
+ GET_BBLOCK (cfg, bblock, target);
ip += 5;
if (ip < end)
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
break;
case MonoInlineSwitch: {
guint32 n = read32 (ip + 1);
ip += 5;
cli_addr += 5 + 4 * n;
target = start + cli_addr;
- GET_BBLOCK (cfg, bbhash, bblock, target);
+ GET_BBLOCK (cfg, bblock, target);
for (j = 0; j < n; ++j) {
target = start + cli_addr + (gint32)read32 (ip);
- GET_BBLOCK (cfg, bbhash, bblock, target);
+ GET_BBLOCK (cfg, bblock, target);
ip += 4;
}
break;
/* Find the start of the bblock containing the throw */
bblock = NULL;
while ((bb_start >= start) && !bblock) {
- bblock = g_hash_table_lookup (bbhash, (bb_start));
+ bblock = cfg->cil_offset_to_bb [(bb_start) - start];
bb_start --;
}
if (bblock)
static gboolean
can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
{
+ if (access_klass->generic_class && member_klass->generic_class &&
+ access_klass->generic_class->container_class && member_klass->generic_class->container_class) {
+ if (can_access_member (access_klass->generic_class->container_class,
+ member_klass->generic_class->container_class, access_level))
+ return TRUE;
+ }
+
/* Partition I 8.5.3.2 */
/* the access level values are the same for fields and methods */
switch (access_level) {
return access_klass == member_klass;
case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
if (mono_class_has_parent (access_klass, member_klass) &&
- can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
+ can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
return TRUE;
return FALSE;
case FIELD_ATTRIBUTE_ASSEMBLY:
return can;
}
+/*
+ * Check that the IL instructions at ip are the array initialization
+ * sequence and return the pointer to the data and the size.
+ */
+static const char*
+initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
+{
+ /*
+ * newarr[System.Int32]
+ * dup
+ * ldtoken field valuetype ...
+ * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
+ */
+ if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
+ MonoClass *klass = newarr->inst_newa_class;
+ guint32 token = read32 (ip + 7);
+ guint32 rva, field_index;
+ const char *data_ptr;
+ int size = 0;
+ MonoMethod *cmethod;
+
+ if (newarr->inst_newa_len->opcode != OP_ICONST)
+ return NULL;
+ cmethod = mini_get_method (method, token, NULL, NULL);
+ if (!cmethod)
+ return NULL;
+ if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
+ return NULL;
+ switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ size = 1; break;
+ /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ size = 2; break;
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_R4:
+ size = 4; break;
+ case MONO_TYPE_R8:
+#ifdef ARM_FPU_FPA
+ return NULL; /* stupid ARM FP swapped format */
+#endif
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ size = 8; break;
+#endif
+ default:
+ return NULL;
+ }
+ size *= newarr->inst_newa_len->inst_c0;
+ *out_size = size;
+ /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
+ field_index = read32 (ip + 2) & 0xffffff;
+ mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
+ data_ptr = mono_image_rva_map (method->klass->image, rva);
+ /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
+ /* for aot code we do the lookup on load */
+ if (aot && data_ptr)
+ return GUINT_TO_POINTER (rva);
+ return data_ptr;
+ }
+ return NULL;
+}
+
/*
* mono_method_to_ir: translates IL into basic blocks containing trees
*/
MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
MonoInst *ins, **sp, **stack_start;
MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
- GHashTable *bbhash;
MonoMethod *cmethod;
MonoInst **arg_array;
MonoMethodHeader *header;
sig = mono_method_signature (method);
num_args = sig->hasthis + sig->param_count;
ip = (unsigned char*)header->code;
+ cfg->cil_start = ip;
end = ip + header->code_size;
mono_jit_stats.cil_code_size += header->code_size;
if (sig->is_inflated)
- generic_context = ((MonoMethodInflated *) method)->context;
+ generic_context = mono_method_get_context (method);
else if (generic_container)
generic_context = &generic_container->context;
g_assert (!sig->has_type_parameters);
- if (cfg->method == method) {
+ if (cfg->method == method)
real_offset = 0;
- bbhash = cfg->bb_hash;
- } else {
+ else
real_offset = inline_offset;
- bbhash = g_hash_table_new (g_direct_hash, NULL);
- }
+
+ cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
+ cfg->cil_offset_to_bb_len = header->code_size;
if (cfg->verbose_level > 2)
g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
for (i = 0; i < header->num_clauses; ++i) {
MonoBasicBlock *try_bb;
MonoExceptionClause *clause = &header->clauses [i];
- GET_BBLOCK (cfg, bbhash, try_bb, ip + clause->try_offset);
+ GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
try_bb->real_offset = clause->try_offset;
- GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
+ GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
tblock->real_offset = clause->handler_offset;
tblock->flags |= BB_EXCEPTION_HANDLER;
tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
- clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+ clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
+ clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
MONO_ADD_INS (tblock, ins);
MONO_ADD_INS (tblock, dummy_use);
if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
- GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
+ GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
tblock->real_offset = clause->data.filter_offset;
tblock->in_scount = 1;
tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
bblock = NEW_BBLOCK (cfg);
bblock->cil_code = ip;
- ADD_BBLOCK (cfg, bbhash, bblock);
+ ADD_BBLOCK (cfg, bblock);
if (cfg->method == method) {
breakpoint_id = mono_debugger_method_has_breakpoint (method);
if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
- MONO_INST_NEW (cfg, ins, CEE_BREAK);
+ MONO_INST_NEW (cfg, ins, OP_BREAK);
MONO_ADD_INS (bblock, ins);
}
}
mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
}
- if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
+ if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
ip = err_pos;
UNVERIFIED;
}
if (start_new_bblock == 2) {
g_assert (ip == tblock->cil_code);
} else {
- GET_BBLOCK (cfg, bbhash, tblock, ip);
+ GET_BBLOCK (cfg, tblock, ip);
}
bblock->next_bb = tblock;
bblock = tblock;
g_slist_free (class_inits);
class_inits = NULL;
} else {
- if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
+ if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
link_bblock (cfg, bblock, tblock);
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
switch (*ip) {
case CEE_NOP:
+ MONO_INST_NEW (cfg, ins, OP_NOP);
+ ins->cil_code = ip++;
+ MONO_ADD_INS (bblock, ins);
+ break;
case CEE_BREAK:
- MONO_INST_NEW (cfg, ins, *ip);
+ MONO_INST_NEW (cfg, ins, OP_BREAK);
ins->cil_code = ip++;
MONO_ADD_INS (bblock, ins);
break;
n = (*ip)-CEE_LDARG_0;
CHECK_ARG (n);
NEW_ARGLOAD (cfg, ins, n);
+ LDARG_SOFT_FLOAT (cfg, ins, n, ip);
ins->cil_code = ip++;
*sp++ = ins;
break;
n = (*ip)-CEE_LDLOC_0;
CHECK_LOCAL (n);
NEW_LOCLOAD (cfg, ins, n);
+ LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
ins->cil_code = ip++;
*sp++ = ins;
break;
ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
UNVERIFIED;
+ STLOC_SOFT_FLOAT (cfg, ins, n, ip);
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, n);
handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
CHECK_STACK_OVF (1);
CHECK_ARG (ip [1]);
NEW_ARGLOAD (cfg, ins, ip [1]);
+ LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
ins->cil_code = ip;
*sp++ = ins;
ip += 2;
ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
UNVERIFIED;
+ STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
if (ins->opcode == CEE_STOBJ) {
NEW_ARGLOADA (cfg, ins, ip [1]);
handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
CHECK_STACK_OVF (1);
CHECK_LOCAL (ip [1]);
NEW_LOCLOAD (cfg, ins, ip [1]);
+ LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
ins->cil_code = ip;
*sp++ = ins;
ip += 2;
ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
UNVERIFIED;
+ STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, ip [1]);
handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
CHECK_OPSIZE (5);
if (stack_start != sp)
UNVERIFIED;
- MONO_INST_NEW (cfg, ins, CEE_JMP);
+ MONO_INST_NEW (cfg, ins, OP_JMP);
token = read32 (ip + 1);
/* FIXME: check the signature matches */
cmethod = mini_get_method (method, token, NULL, generic_context);
} else if (constrained_call) {
cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
cmethod = mono_get_inflated_method (cmethod);
+ cil_method = cmethod;
} else {
cmethod = mini_get_method (method, token, NULL, generic_context);
cil_method = cmethod;
fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
}
+ mono_save_token_info (cfg, image, token, cmethod);
+
n = fsig->param_count + fsig->hasthis;
if (mono_use_security_manager) {
this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
this_arg_temp->cil_code = ip;
+ /* Because of the PCONST below */
+ cfg->disable_aot = TRUE;
NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
- NEW_PCONST (cfg, iargs [1], cmethod);
- NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
+ NEW_METHODCONST (cfg, iargs [1], cmethod);
+ NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
/* Prevent inlining of methods with tail calls (the call stack would be altered) */
INLINE_FAILURE;
/* FIXME: This assumes the two methods has the same number and type of arguments */
+ /*
+ * We implement tail calls by storing the actual arguments into the
+ * argument variables, then emitting a OP_JMP. Since the actual arguments
+ * can refer to the arg variables, we have to spill them.
+ */
+ handle_loaded_temps (cfg, bblock, sp, sp + n);
for (i = 0; i < n; ++i) {
+ /* Prevent argument from being register allocated */
+ arg_array [i]->flags |= MONO_INST_VOLATILE;
+
/* Check if argument is the same */
+ /*
+ * FIXME: This loses liveness info, so it can only be done if the
+ * argument is not register allocated.
+ */
NEW_ARGLOAD (cfg, ins, i);
if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
continue;
- /* Prevent argument from being register allocated */
- arg_array [i]->flags |= MONO_INST_VOLATILE;
NEW_ARGSTORE (cfg, ins, i, sp [i]);
ins->cil_code = ip;
if (ins->opcode == CEE_STOBJ) {
else
MONO_ADD_INS (bblock, ins);
}
- MONO_INST_NEW (cfg, ins, CEE_JMP);
+ MONO_INST_NEW (cfg, ins, OP_JMP);
ins->cil_code = ip;
ins->inst_p0 = cmethod;
ins->inst_p1 = arg_array [0];
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
}
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
tblock = start_bblock->out_bb [0];
g_assert (!return_var);
CHECK_STACK (1);
--sp;
- MONO_INST_NEW (cfg, ins, CEE_NOP);
+ MONO_INST_NEW (cfg, ins, OP_NOP);
ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
if (ins->opcode == CEE_STOBJ) {
NEW_RETLOADA (cfg, ins);
}
if (sp != stack_start)
UNVERIFIED;
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip++;
ins->inst_target_bb = end_bblock;
MONO_ADD_INS (bblock, ins);
break;
case CEE_BR_S:
CHECK_OPSIZE (2);
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip++;
MONO_ADD_INS (bblock, ins);
target = ip + 1 + (signed char)(*ip);
++ip;
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
CHECK_BBLOCK (target, ip, tblock);
ins->inst_target_bb = tblock;
ins->cil_code = ip++;
target = ip + 1 + *(signed char*)ip;
ip++;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
+ ins->opcode = condbr_to_fp_br (ins->opcode);
+ sp -= 2;
+ ins->inst_left = sp [0];
+ ins->inst_right = sp [1];
+ ins->type = STACK_I4;
+ *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
+ MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
+ ADD_UNCOND (TRUE);
+ } else {
+ ADD_BINCOND (NULL);
+ }
+#else
ADD_BINCOND (NULL);
+#endif
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
break;
case CEE_BR:
CHECK_OPSIZE (5);
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip++;
MONO_ADD_INS (bblock, ins);
target = ip + 4 + (gint32)read32(ip);
ip += 4;
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
CHECK_BBLOCK (target, ip, tblock);
ins->inst_target_bb = tblock;
ins->cil_code = ip++;
target = ip + 4 + (gint32)read32(ip);
ip += 4;
- ADD_BINCOND(NULL);
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
+ ins->opcode = condbr_to_fp_br (ins->opcode);
+ sp -= 2;
+ ins->inst_left = sp [0];
+ ins->inst_right = sp [1];
+ ins->type = STACK_I4;
+ *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
+ MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
+ ADD_UNCOND (TRUE);
+ } else {
+ ADD_BINCOND (NULL);
+ }
+#else
+ ADD_BINCOND (NULL);
+#endif
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
CHECK_OPSIZE (n * sizeof (guint32));
target = ip + n * sizeof (guint32);
MONO_ADD_INS (bblock, ins);
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
ins->klass = GUINT_TO_POINTER (n);
ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
ins->inst_many_bb [n] = tblock;
for (i = 0; i < n; ++i) {
- GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
+ GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
link_bblock (cfg, bblock, tblock);
ins->inst_many_bb [i] = tblock;
ip += 4;
ins_flag = 0;
if (ins->type == STACK_OBJ)
ins->klass = mono_defaults.object_class;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (*ip == CEE_LDIND_R4) {
+ int temp;
+ --sp;
+ temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ sp++;
+ }
+#endif
++ip;
break;
case CEE_STIND_REF:
case CEE_STIND_R4:
case CEE_STIND_R8:
CHECK_STACK (2);
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (*ip == CEE_STIND_R4) {
+ sp -= 2;
+ handle_store_float (cfg, bblock, sp [0], sp [1], ip);
+ ip++;
+ break;
+ }
+#endif
#if HAVE_WRITE_BARRIERS
if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
/* insert call to write barrier */
CHECK_STACK (2);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
sp -= 2;
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MonoInst *store, *load;
--sp;
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
ins->cil_code = ip;
n = read32 (ip + 1);
if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
+ /* FIXME: moving GC */
NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
ins->cil_code = ip;
ins->type = STACK_OBJ;
MonoInst* domain_var;
if (cfg->compile_aot) {
+ /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
}
/* avoid depending on undefined C behavior in sequence points */
goto load_error;
fsig = mono_method_get_signature (cmethod, image, token);
+ mono_save_token_info (cfg, image, token, cmethod);
+
if (!mono_class_init (cmethod->klass))
goto load_error;
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
/* CASTCLASS */
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (mono_class_is_nullable (klass)) {
int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
break;
case CEE_THROW:
CHECK_STACK (1);
- MONO_INST_NEW (cfg, ins, *ip);
+ MONO_INST_NEW (cfg, ins, OP_THROW);
--sp;
ins->inst_left = *sp;
ins->cil_code = ip++;
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
iargs [0] = ins;
iargs [1] = sp [1];
mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
+#endif
+#ifdef MONO_ARCH_SOFT_FLOAT
+ } else if (mono_type_to_stind (field->type) == CEE_STIND_R4) {
+ NEW_ICONST (cfg, offset_ins, foffset);
+ MONO_INST_NEW (cfg, ins, OP_PADD);
+ ins->cil_code = ip;
+ ins->inst_left = *sp;
+ ins->inst_right = offset_ins;
+ ins->type = STACK_MP;
+ ins->klass = mono_defaults.object_class;
+ handle_store_float (cfg, bblock, ins, sp [1], ip);
#endif
} else {
MonoInst *store;
ip += 5;
real_offset += 5;
- GET_BBLOCK (cfg, bbhash, bblock, ip);
+ GET_BBLOCK (cfg, bblock, ip);
ebblock->next_bb = bblock;
link_bblock (cfg, ebblock, bblock);
load->inst_left = ins;
load->flags |= ins_flag;
ins_flag = 0;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (mono_type_to_ldind (field->type) == CEE_LDIND_R4) {
+ int temp;
+ temp = handle_load_float (cfg, bblock, ins, ip);
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ sp++;
+ } else
+#endif
*sp++ = load;
}
}
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
n = mono_type_to_stind (&klass->byval_arg);
if (n == CEE_STOBJ) {
handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
*sp++ = val;
ins->cil_code = ip;
ins->inst_i0 = *sp;
ip += 5;
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
if (*ip == CEE_BRTRUE_S) {
target = ip + 4 + (gint)(read32 (ip));
ip += 4;
}
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
CHECK_BBLOCK (target, ip, tblock);
ins->inst_target_bb = tblock;
+ GET_BBLOCK (cfg, tblock, ip);
+ link_bblock (cfg, bblock, tblock);
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
mono_get_got_var (cfg);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
ins->inst_newa_class = klass;
ins->inst_newa_len = *sp;
ins->type = STACK_OBJ;
- ins->klass = klass;
+ ins->klass = mono_array_class_get (klass, 1);
ip += 5;
*sp++ = ins;
/*
*/
if (1) {
MonoInst *store, *temp, *load;
+ const char *data_ptr;
+ int data_size = 0;
--sp;
temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
store->cil_code = ins->cil_code;
MONO_ADD_INS (bblock, store);
+ /*
+ * we inline/optimize the initialization sequence if possible.
+ * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
+ * for small sizes open code the memcpy
+ * ensure the rva field is big enough
+ */
+ if ((cfg->opt & MONO_OPT_INTRINS) && ip_in_bb (cfg, bblock, ip + 6) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, ins, &data_size))) {
+ MonoMethod *memcpy_method = get_memcpy_method ();
+ MonoInst *data_offset, *add;
+ MonoInst *iargs [3];
+ NEW_ICONST (cfg, iargs [2], data_size);
+ NEW_TEMPLOAD (cfg, load, temp->inst_c0);
+ load->cil_code = ins->cil_code;
+ NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
+ MONO_INST_NEW (cfg, add, OP_PADD);
+ add->inst_left = load;
+ add->inst_right = data_offset;
+ add->cil_code = ip;
+ iargs [0] = add;
+ if (cfg->compile_aot) {
+ NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
+ } else {
+ NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
+ }
+ mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
+ ip += 11;
+ }
NEW_TEMPLOAD (cfg, load, temp->inst_c0);
load->cil_code = ins->cil_code;
*sp++ = load;
UNVERIFIED;
klass = mini_get_class (method, read32 (ip + 1), generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
/* we need to make sure that this array is exactly the type it needs
* to be for correctness. the wrappers are lax with their usage
* so we need to ignore them here
*/
if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
MonoInst* check;
+
+ /* Needed by the code generated in inssel.brg */
+ mono_get_got_var (cfg);
+
MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
check->cil_code = ip;
check->klass = klass;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mono_class_get_full (image, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
sp -= 2;
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
- klass = array_access_to_klass (*ip);
+ klass = array_access_to_klass (*ip, sp [0]);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (*ip == CEE_LDELEM_R4) {
+ int temp;
+ temp = handle_load_float (cfg, bblock, load, ip);
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ sp++;
+ ++ip;
+ break;
+ }
+#endif
MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
ins->cil_code = ip;
ins->inst_left = load;
sp -= 3;
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
- klass = array_access_to_klass (*ip);
+ klass = array_access_to_klass (*ip, sp [0]);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (*ip == CEE_STELEM_R4) {
+ handle_store_float (cfg, bblock, load, sp [2], ip);
+ ip++;
+ break;
+ }
+#endif
MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
ins->cil_code = ip;
ins->inst_left = load;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mono_class_get_full (image, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
- MonoMethod* helper = mono_marshal_get_stelemref ();
- MonoInst *iargs [3];
- handle_loaded_temps (cfg, bblock, stack_start, sp);
+ /* storing a NULL doesn't need any of the complex checks in stelemref */
+ if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
+ MonoInst *load;
+ NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
+ load->cil_code = ip;
+ MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+ ins->cil_code = ip;
+ ins->inst_left = load;
+ ins->inst_right = sp [2];
+ MONO_ADD_INS (bblock, ins);
+ } else {
+ MonoMethod* helper = mono_marshal_get_stelemref ();
+ MonoInst *iargs [3];
+ handle_loaded_temps (cfg, bblock, stack_start, sp);
- iargs [2] = sp [2];
- iargs [1] = sp [1];
- iargs [0] = sp [0];
-
- mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+ iargs [2] = sp [2];
+ iargs [1] = sp [1];
+ iargs [0] = sp [0];
+
+ mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+ }
} else {
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
handle_loaded_temps (cfg, bblock, stack_start, sp);
- iargs [2] = sp [2];
- iargs [1] = sp [1];
- iargs [0] = sp [0];
+ /* storing a NULL doesn't need any of the complex checks in stelemref */
+ if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
+ MonoInst *load;
+ NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
+ load->cil_code = ip;
+ MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+ ins->cil_code = ip;
+ ins->inst_left = load;
+ ins->inst_right = sp [2];
+ MONO_ADD_INS (bblock, ins);
+ } else {
+ iargs [2] = sp [2];
+ iargs [1] = sp [1];
+ iargs [0] = sp [0];
- mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
-
- /*
- MonoInst *group;
- NEW_GROUP (cfg, group, sp [0], sp [1]);
- MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
- ins->cil_code = ip;
- ins->inst_left = group;
- ins->inst_right = sp [2];
- MONO_ADD_INS (bblock, ins);
- */
+ mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+ inline_costs += 1;
+ }
++ip;
- inline_costs += 1;
break;
}
case CEE_CKFINITE: {
* this check */
- MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
+ MONO_INST_NEW (cfg, ins, OP_CKFINITE);
ins->cil_code = ip;
ins->inst_left = sp [-1];
temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
--sp;
CHECK_OPSIZE (5);
klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
ins->type = STACK_MP;
ins->inst_left = *sp;
--sp;
CHECK_OPSIZE (5);
klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
ins->cil_code = ip;
ip++;
break;
case CEE_ENDFINALLY:
- MONO_INST_NEW (cfg, ins, *ip);
+ MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
MONO_ADD_INS (bblock, ins);
ins->cil_code = ip++;
start_new_bblock = 1;
}
}
- /* fixme: call fault handler ? */
-
if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
GList *tmp;
for (tmp = handlers; tmp; tmp = tmp->next) {
g_list_free (handlers);
}
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
- GET_BBLOCK (cfg, bbhash, tblock, target);
+ GET_BBLOCK (cfg, tblock, target);
link_bblock (cfg, bblock, tblock);
CHECK_BBLOCK (target, ip, tblock);
ins->inst_target_bb = tblock;
token = read32 (ip + 2);
func = mono_method_get_wrapper_data (method, token);
info = mono_find_jit_icall_by_addr (func);
- g_assert (info);
+ if (info == NULL){
+ g_error ("An attempt has been made to perform an icall to address %p, "
+ "but the address has not been registered as an icall\n", info);
+ g_assert_not_reached ();
+ }
CHECK_STACK (info->sig->param_count);
sp -= info->sig->param_count;
if (sp != stack_start)
UNVERIFIED;
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
ins->cil_code = ip;
ins->inst_target_bb = end_bblock;
MONO_ADD_INS (bblock, ins);
cmp->cil_code = ip;
type_from_op (cmp);
CHECK_TYPE (cmp);
+ ins->cil_code = ip;
+ ins->type = STACK_I4;
+ ins->inst_i0 = cmp;
+#if MONO_ARCH_SOFT_FLOAT
+ if (sp [0]->type == STACK_R8) {
+ cmp->type = STACK_I4;
+ *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
+ ip += 2;
+ break;
+ }
+#endif
if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
cmp->opcode = OP_LCOMPARE;
else
cmp->opcode = OP_COMPARE;
- ins->cil_code = ip;
- ins->type = STACK_I4;
- ins->inst_i0 = cmp;
*sp++ = ins;
/* spill it to reduce the expression complexity
* and workaround bug 54209
n = read16 (ip + 2);
CHECK_ARG (n);
NEW_ARGLOAD (cfg, ins, n);
+ LDARG_SOFT_FLOAT (cfg, ins, n, ip);
ins->cil_code = ip;
*sp++ = ins;
ip += 4;
ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
UNVERIFIED;
+ STARG_SOFT_FLOAT (cfg, ins, n, ip);
if (ins->opcode == CEE_STOBJ) {
NEW_ARGLOADA (cfg, ins, n);
handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
n = read16 (ip + 2);
CHECK_LOCAL (n);
NEW_LOCLOAD (cfg, ins, n);
+ LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
ins->cil_code = ip;
*sp++ = ins;
ip += 4;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
UNVERIFIED;
ins->cil_code = ip;
+ STLOC_SOFT_FLOAT (cfg, ins, n, ip);
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, n);
handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
CHECK_OPSIZE (6);
token = read32 (ip + 2);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MonoInst *store, *load;
NEW_PCONST (cfg, load, NULL);
CHECK_OPSIZE (6);
token = read32 (ip + 2);
constrained_call = mono_class_get_full (image, token, generic_context);
- if (!constrained_call)
- goto load_error;
+ CHECK_TYPELOAD (constrained_call);
ip += 6;
break;
case CEE_CPBLK:
token = mono_type_size (type, &ialign);
} else {
MonoClass *klass = mono_class_get_full (image, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
token = mono_class_value_size (klass, &align);
}
NEW_LOCSTORE (cfg, store, i, ins);
MONO_ADD_INS (init_localsbb, store);
} else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
+#ifdef MONO_ARCH_SOFT_FLOAT
+ /* FIXME: handle init of R4 */
+#else
MONO_INST_NEW (cfg, ins, OP_R8CONST);
ins->type = STACK_R8;
ins->inst_p0 = (void*)&r8_0;
NEW_LOCSTORE (cfg, store, i, ins);
MONO_ADD_INS (init_localsbb, store);
+#endif
} else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
NEW_LOCLOADA (cfg, ins, i);
for (tmp = bb_recheck; tmp; tmp = tmp->next) {
bblock = tmp->data;
/*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
- tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
+ tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
if (tblock != start_bblock) {
int l;
split_bblock (cfg, tblock, bblock);
if (cfg->verbose_level > 2)
g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
}
- } else {
- g_hash_table_destroy (bbhash);
}
g_slist_free (class_inits);
return inline_costs;
inline_failure:
- if (cfg->method != method)
- g_hash_table_destroy (bbhash);
g_slist_free (class_inits);
dont_inline = g_list_remove (dont_inline, method);
return -1;
load_error:
- if (cfg->method != method)
- g_hash_table_destroy (bbhash);
g_slist_free (class_inits);
dont_inline = g_list_remove (dont_inline, method);
cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
return -1;
unverified:
- if (cfg->method != method)
- g_hash_table_destroy (bbhash);
g_slist_free (class_inits);
dont_inline = g_list_remove (dont_inline, method);
cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
}
case OP_RENAME:
case OP_RETARG:
- case CEE_NOP:
- case CEE_JMP:
- case CEE_BREAK:
+ case OP_NOP:
+ case OP_JMP:
+ case OP_BREAK:
break;
case OP_LOAD_MEMBASE:
case OP_LOADI4_MEMBASE:
case OP_LOADI2_MEMBASE:
printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
break;
- case CEE_BR:
+ case OP_BR:
case OP_CALL_HANDLER:
printf ("[B%d]", tree->inst_target_bb->block_num);
break;
#endif
static gpointer
-mono_create_delegate_trampoline (MonoMethod *method, gpointer addr)
+mono_create_delegate_trampoline (MonoClass *klass)
{
#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
+ MonoDomain *domain = mono_domain_get ();
gpointer code, ptr;
guint32 code_size;
- MonoDomain *domain = mono_domain_get ();
-
-#ifndef __ia64__
- code = mono_jit_find_compiled_method (domain, method);
- if (code)
- return code;
-#else
- /*
- * FIXME: We should return a function descriptor here but it is not stored
- * anywhere so it would be leaked.
- */
-#endif
mono_domain_lock (domain);
- ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, method);
+ ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, klass);
mono_domain_unlock (domain);
if (ptr)
return ptr;
- code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
+ code = mono_arch_create_specific_trampoline (klass, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size);
ptr = mono_create_ftnptr (domain, code);
/* store trampoline address */
mono_domain_lock (domain);
g_hash_table_insert (domain->delegate_trampoline_hash,
- method, ptr);
+ klass, ptr);
mono_domain_unlock (domain);
return ptr;
#else
- return addr;
+ return NULL;
#endif
}
typedef struct {
MonoClass *vtype;
GList *active;
- GList *slots;
+ GSList *slots;
} StackSlotInfo;
+static inline GSList*
+g_slist_prepend_mempool (MonoMemPool *mp, GSList *list,
+ gpointer data)
+{
+ GSList *new_list;
+
+ new_list = mono_mempool_alloc (mp, sizeof (GSList));
+ new_list->data = data;
+ new_list->next = list;
+
+ return new_list;
+}
+
/*
* mono_allocate_stack_slots_full:
*
* Allocate stack slots for all non register allocated variables using a
* linear scan algorithm.
- * Returns: an array of stack offsets which the caller should free.
+ * Returns: an array of stack offsets.
* STACK_SIZE is set to the amount of stack space needed.
* STACK_ALIGN is set to the alignment needed by the locals area.
*/
MonoType *t;
int nvtypes;
- scalar_stack_slots = g_new0 (StackSlotInfo, MONO_TYPE_PINNED);
- vtype_stack_slots = g_new0 (StackSlotInfo, 256);
+ scalar_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
+ vtype_stack_slots = NULL;
nvtypes = 0;
- offsets = g_new (gint32, m->num_varinfo);
+ offsets = mono_mempool_alloc (m->mempool, sizeof (gint32) * m->num_varinfo);
for (i = 0; i < m->num_varinfo; ++i)
offsets [i] = -1;
}
/* Fall through */
case MONO_TYPE_VALUETYPE:
+ if (!vtype_stack_slots)
+ vtype_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * 256);
for (i = 0; i < nvtypes; ++i)
if (t->data.klass == vtype_stack_slots [i].vtype)
break;
nvtypes ++;
}
break;
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 4
+ case MONO_TYPE_I4:
+#else
+ case MONO_TYPE_I8:
+#endif
+ /* Share non-float stack slots of the same size */
+ slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
+ break;
default:
slot_info = &scalar_stack_slots [t->type];
}
//printf ("EXPIR %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
- slot_info->slots = g_list_prepend (slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
+ slot_info->slots = g_slist_prepend_mempool (m->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
}
/*
if (slot_info->slots) {
slot = GPOINTER_TO_INT (slot_info->slots->data);
- slot_info->slots = g_list_delete_link (slot_info->slots, slot_info->slots);
+ slot_info->slots = slot_info->slots->next;
}
slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
}
g_list_free (vars);
for (i = 0; i < MONO_TYPE_PINNED; ++i) {
- g_list_free (scalar_stack_slots [i].active);
- g_list_free (scalar_stack_slots [i].slots);
+ if (scalar_stack_slots [i].active)
+ g_list_free (scalar_stack_slots [i].active);
}
for (i = 0; i < nvtypes; ++i) {
- g_list_free (vtype_stack_slots [i].active);
- g_list_free (vtype_stack_slots [i].slots);
+ if (vtype_stack_slots [i].active)
+ g_list_free (vtype_stack_slots [i].active);
}
- g_free (scalar_stack_slots);
- g_free (vtype_stack_slots);
+
+ mono_jit_stats.locals_stack_size += offset;
*stack_size = offset;
return offsets;
dec_foreach (iargs [i], cfg);
break;
}
+#ifdef MONO_ARCH_SOFT_FLOAT
+ case OP_FBEQ:
+ case OP_FBGE:
+ case OP_FBGT:
+ case OP_FBLE:
+ case OP_FBLT:
+ case OP_FBNE_UN:
+ case OP_FBGE_UN:
+ case OP_FBGT_UN:
+ case OP_FBLE_UN:
+ case OP_FBLT_UN: {
+ if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+ MonoCompile *cfg = data;
+ MonoInst *iargs [2];
+
+ iargs [0] = tree->inst_i0;
+ iargs [1] = tree->inst_i1;
+
+ mono_emulate_opcode (cfg, tree, iargs, info);
+
+ dec_foreach (iargs [0], cfg);
+ dec_foreach (iargs [1], cfg);
+ break;
+ } else {
+ g_assert_not_reached ();
+ }
+ break;
+ }
+ case OP_FCEQ:
+ case OP_FCGT:
+ case OP_FCGT_UN:
+ case OP_FCLT:
+ case OP_FCLT_UN: {
+ if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+ MonoCompile *cfg = data;
+ MonoInst *iargs [2];
+
+ /* the args are in the compare opcode ... */
+ iargs [0] = tree->inst_i0;
+ iargs [1] = tree->inst_i1;
+
+ mono_emulate_opcode (cfg, tree, iargs, info);
+
+ dec_foreach (iargs [0], cfg);
+ dec_foreach (iargs [1], cfg);
+ break;
+ } else {
+ g_assert_not_reached ();
+ }
+ break;
+ }
+#endif
default:
break;
mono_destroy_compile (MonoCompile *cfg)
{
//mono_mempool_stats (cfg->mempool);
- g_hash_table_destroy (cfg->bb_hash);
mono_free_loop_info (cfg);
if (cfg->rs)
mono_regstate_free (cfg->rs);
g_hash_table_destroy (cfg->exvars);
mono_mempool_destroy (cfg->mempool);
g_list_free (cfg->ldstr_list);
+ g_hash_table_destroy (cfg->token_info_hash);
g_free (cfg->varinfo);
g_free (cfg->vars);
#ifdef HAVE_KW_THREAD
static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
+#ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
+/*
+ * When this is defined, the current lmf is stored in this tls variable instead of in
+ * jit_tls->lmf.
+ */
+static __thread gpointer mono_lmf MONO_TLS_FAST;
+#endif
#endif
guint32
gint32
mono_get_lmf_tls_offset (void)
+{
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+ int offset;
+ MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
+ return offset;
+#else
+ return -1;
+#endif
+}
+
+gint32
+mono_get_lmf_addr_tls_offset (void)
{
int offset;
MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
return offset;
}
+MonoLMF *
+mono_get_lmf (void)
+{
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+ return mono_lmf;
+#else
+ MonoJitTlsData *jit_tls;
+
+ if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
+ return jit_tls->lmf;
+
+ g_assert_not_reached ();
+ return NULL;
+#endif
+}
+
MonoLMF **
mono_get_lmf_addr (void)
{
lmf = g_new0 (MonoLMF, 1);
lmf->ebp = -1;
- jit_tls->lmf = jit_tls->first_lmf = lmf;
+ jit_tls->first_lmf = lmf;
-#ifdef HAVE_KW_THREAD
- mono_lmf_addr = &jit_tls->lmf;
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+ /* jit_tls->lmf is unused */
+ mono_lmf = lmf;
+ mono_lmf_addr = &mono_lmf;
+#else
+#if defined(HAVE_KW_THREAD)
+ mono_lmf_addr = &jit_tls->lmf;
+#endif
+
+ jit_tls->lmf = lmf;
#endif
mono_arch_setup_jit_tls_data (jit_tls);
memcpy (res, patch_info, sizeof (MonoJumpInfo));
switch (patch_info->type) {
+ case MONO_PATCH_INFO_RVA:
case MONO_PATCH_INFO_LDSTR:
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
case MONO_PATCH_INFO_LDTOKEN:
const MonoJumpInfo *ji = (MonoJumpInfo*)data;
switch (ji->type) {
+ case MONO_PATCH_INFO_RVA:
case MONO_PATCH_INFO_LDSTR:
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
case MONO_PATCH_INFO_LDTOKEN:
return 0;
switch (ji1->type) {
+ case MONO_PATCH_INFO_RVA:
case MONO_PATCH_INFO_LDSTR:
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
case MONO_PATCH_INFO_LDTOKEN:
target = (char*)vtable->data + patch_info->data.field->offset;
break;
}
+ case MONO_PATCH_INFO_RVA:
+ target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
+ break;
case MONO_PATCH_INFO_R4:
case MONO_PATCH_INFO_R8:
target = patch_info->data.target;
}
if (bb->last_ins != NULL) {
switch (bb->last_ins->opcode) {
- case CEE_BR:
+ case OP_BR:
if (bb->last_ins->inst_target_bb == orig) {
bb->last_ins->inst_target_bb = repl;
}
for (inst = bb->code; inst != NULL; inst = inst->next) {
switch (inst->opcode) {
- case CEE_NOP:
+ case OP_NOP:
break;
- case CEE_BR:
+ case OP_BR:
target_bb = inst->inst_target_bb;
break;
default:
if ((previous_bb != cfg->bb_entry) &&
(previous_bb->region == bb->region) &&
((previous_bb->last_ins == NULL) ||
- ((previous_bb->last_ins->opcode != CEE_BR) &&
+ ((previous_bb->last_ins->opcode != OP_BR) &&
(! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
(previous_bb->last_ins->opcode != CEE_SWITCH)))) {
for (i = 0; i < previous_bb->out_count; i++) {
if (previous_bb->out_bb [i] == target_bb) {
MonoInst *jump;
- MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_INST_NEW (cfg, jump, OP_BR);
MONO_ADD_INS (previous_bb, jump);
jump->cil_code = previous_bb->cil_code;
jump->inst_target_bb = target_bb;
/* Nullify branch at the end of bb */
if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
- bb->last_ins->opcode = CEE_NOP;
+ bb->last_ins->opcode = OP_NOP;
}
if (bb->last_ins) {
if (next && (!bb->last_ins || (bb->last_ins->opcode != OP_NOT_REACHED))) {
MonoInst *ins;
- MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_INST_NEW (cfg, ins, OP_BR);
MONO_ADD_INS (bb, ins);
link_bblock (cfg, bb, next);
ins->inst_target_bb = next;
return FALSE;
condb->opcode = get_unsigned_condbranch (condb->opcode);
/* change the original condbranch to just point to the new unsigned check */
- bb->last_ins->opcode = CEE_BR;
+ bb->last_ins->opcode = OP_BR;
bb->last_ins->inst_target_bb = falset;
replace_out_block (bb, truet, NULL);
replace_in_block (truet, bb, NULL);
if (bb->out_count == 1) {
bbn = bb->out_bb [0];
- /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
+ /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
MonoInst *pop;
MONO_INST_NEW (cfg, pop, CEE_POP);
MONO_INST_NEW (cfg, pop, CEE_POP);
pop->inst_left = bb->last_ins->inst_left->inst_right;
mono_add_ins_to_end (bb, pop);
- bb->last_ins->opcode = CEE_BR;
+ bb->last_ins->opcode = OP_BR;
bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
changed = TRUE;
if (cfg->verbose_level > 2)
/* the block are in sequence anyway ... */
/* branches to the following block can be removed */
- if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
- bb->last_ins->opcode = CEE_NOP;
+ if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
+ bb->last_ins->opcode = OP_NOP;
changed = TRUE;
if (cfg->verbose_level > 2)
g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
if (bb->out_count == 1) {
bbn = bb->out_bb [0];
- if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
+ if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
bbn = bb->last_ins->inst_target_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+ if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
bbn->code->inst_target_bb->region == bb->region) {
if (cfg->verbose_level > 2)
/* if mono_eval_cond_branch () is ever taken to handle
* non-constant values to compare, issue a pop here.
*/
- bb->last_ins->opcode = CEE_BR;
+ bb->last_ins->opcode = OP_BR;
bb->last_ins->inst_target_bb = taken_branch_target;
mono_unlink_bblock (cfg, bb, untaken_branch_target);
changed = TRUE;
continue;
}
bbn = bb->last_ins->inst_true_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+ if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
bbn->code->inst_target_bb->region == bb->region) {
if (cfg->verbose_level > 2)
g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n",
}
bbn = bb->last_ins->inst_false_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+ if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
bbn->code->inst_target_bb->region == bb->region) {
if (cfg->verbose_level > 2)
g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n",
if (cfg->verbose_level > 2)
g_print ("creating vars\n");
+ cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
+
if (sig->hasthis)
- mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
+ cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
for (i = 0; i < sig->param_count; ++i) {
- mono_compile_create_var (cfg, sig->params [i], OP_ARG);
+ cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
if (sig->params [i]->byref) {
cfg->disable_ssa = TRUE;
}
state->reg2 = mono_regstate_next_int (cfg->rs);
break;
case MB_NTERM_freg:
+#ifdef MONO_ARCH_SOFT_FLOAT
+ state->reg1 = mono_regstate_next_int (cfg->rs);
+ state->reg2 = mono_regstate_next_int (cfg->rs);
+#else
state->reg1 = mono_regstate_next_float (cfg->rs);
+#endif
break;
default:
#ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
} else {
MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
- inst->opcode = CEE_BR;
+ inst->opcode = OP_BR;
inst->inst_target_bb = bb->last_ins->inst_false_bb;
mono_bblock_add_inst (bb, inst);
}
}
emit_state (cfg, mbstate, MB_NTERM_stmt);
}
- bb->max_ireg = cfg->rs->next_vireg;
- bb->max_freg = cfg->rs->next_vfreg;
+ bb->max_vreg = cfg->rs->next_vreg;
if (bb->last_ins)
bb->last_ins->next = NULL;
if (previous_bb->region == bb->region) {
if (previous_bb != cfg->bb_entry) {
/* If previous_bb "followed through" to bb, */
- /* keep it linked with a CEE_BR */
+ /* keep it linked with a OP_BR */
if ((previous_bb->last_ins == NULL) ||
- ((previous_bb->last_ins->opcode != CEE_BR) &&
+ ((previous_bb->last_ins->opcode != OP_BR) &&
(! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
(previous_bb->last_ins->opcode != CEE_SWITCH))) {
int i;
for (i = 0; i < previous_bb->out_count; i++) {
if (previous_bb->out_bb [i] == bb) {
MonoInst *jump;
- MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_INST_NEW (cfg, jump, OP_BR);
MONO_ADD_INS (previous_bb, jump);
jump->cil_code = previous_bb->cil_code;
jump->inst_target_bb = bb;
}
} else {
/* We cannot add any inst to the entry BB, so we must */
- /* put a new BB in the middle to hold the CEE_BR */
+ /* put a new BB in the middle to hold the OP_BR */
MonoInst *jump;
MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
new_bb_after_entry->block_num = cfg->num_bblocks++;
// new_bb_after_entry->real_offset = bb->real_offset;
new_bb_after_entry->region = bb->region;
- MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_INST_NEW (cfg, jump, OP_BR);
MONO_ADD_INS (new_bb_after_entry, jump);
jump->cil_code = bb->cil_code;
jump->inst_target_bb = bb;
cfg->opt = opts;
cfg->prof_options = mono_profiler_get_events ();
cfg->run_cctors = run_cctors;
- cfg->bb_hash = g_hash_table_new (NULL, NULL);
cfg->domain = domain;
cfg->verbose_level = mini_verbose;
cfg->compile_aot = compile_aot;
cfg->skip_visibility = method->skip_visibility;
+ cfg->token_info_hash = g_hash_table_new (NULL, NULL);
if (!header) {
cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
g_list_free (regs);
}
+ /* todo: remove code when we have verified that the liveness for try/catch blocks
+ * works perfectly
+ */
+ /*
+ * Currently, this can't be commented out since exception blocks are not
+ * processed during liveness analysis.
+ */
+ mono_liveness_handle_exception_clauses (cfg);
+
if (cfg->opt & MONO_OPT_LINEARS) {
GList *vars, *regs;
ei->exvar_offset = exvar ? exvar->inst_offset : 0;
if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
- tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
+ tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
g_assert (tblock);
ei->data.filter = cfg->native_code + tblock->native_offset;
} else {
ei->data.catch_class = ec->data.catch_class;
}
- tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
+ tblock = cfg->cil_offset_to_bb [ec->try_offset];
g_assert (tblock);
ei->try_start = cfg->native_code + tblock->native_offset;
g_assert (tblock->native_offset);
- tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
+ tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
g_assert (tblock);
ei->try_end = cfg->native_code + tblock->native_offset;
g_assert (tblock->native_offset);
- tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
+ tblock = cfg->cil_offset_to_bb [ec->handler_offset];
g_assert (tblock);
ei->handler_start = cfg->native_code + tblock->native_offset;
}
mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
{
MonoCompile *cfg;
- GHashTable *jit_code_hash;
gpointer code = NULL;
MonoJitInfo *info;
- jit_code_hash = target_domain->jit_code_hash;
-
method = mono_get_inflated_method (method);
#ifdef MONO_USE_AOT_COMPILER
if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
- MonoJitInfo *info;
MonoDomain *domain = mono_domain_get ();
- mono_domain_lock (domain);
-
mono_class_init (method->klass);
- if ((info = mono_aot_get_method (domain, method))) {
- g_hash_table_insert (domain->jit_code_hash, method, info);
+
+ mono_domain_lock (domain);
+ if ((code = mono_aot_get_method (domain, method))) {
mono_domain_unlock (domain);
mono_runtime_class_init (mono_class_vtable (domain, method->klass));
- return info->code_start;
+ return code;
}
mono_domain_unlock (domain);
/* Throw a type load exception if needed */
MonoLoaderError *error = mono_loader_get_last_error ();
- mono_destroy_compile (cfg);
if (error) {
MonoException *ex = mono_loader_error_prepare_exception (error);
+ mono_destroy_compile (cfg);
mono_raise_exception (ex);
} else {
+ if (cfg->exception_ptr) {
+ MonoException *ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
+ mono_destroy_compile (cfg);
+ mono_raise_exception (ex);
+ }
g_assert_not_reached ();
}
}
/* Check if some other thread already did the job. In this case, we can
discard the code this thread generated. */
- if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+ if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
/* We can't use a domain specific method in another domain */
if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
code = info->code_start;
}
if (code == NULL) {
- g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
+ mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
code = cfg->native_code;
}
mono_domain_lock (target_domain);
- if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+ if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
/* We can't use a domain specific method in another domain */
if (! ((domain != target_domain) && !info->domain_neutral)) {
mono_domain_unlock (target_domain);
return;
mono_domain_lock (domain);
g_hash_table_remove (domain->dynamic_code_hash, method);
- g_hash_table_remove (domain->jit_code_hash, method);
+ mono_internal_hash_table_remove (&domain->jit_code_hash, method);
g_hash_table_remove (domain->jump_trampoline_hash, method);
mono_domain_unlock (domain);
mono_domain_lock (target_domain);
- if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+ if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
/* We can't use a domain specific method in another domain */
if (! ((domain != target_domain) && !info->domain_neutral)) {
mono_domain_unlock (target_domain);
return runtime_invoke (obj, params, exc, compiled_method);
}
+#ifdef MONO_GET_CONTEXT
+#define GET_CONTEXT MONO_GET_CONTEXT
+#endif
+
+#ifndef GET_CONTEXT
#ifdef PLATFORM_WIN32
#define GET_CONTEXT \
struct sigcontext *ctx = (struct sigcontext*)_dummy;
#else
-#ifdef __sparc
+#ifdef MONO_ARCH_USE_SIGACTION
#define GET_CONTEXT \
void *ctx = context;
-#elif defined (MONO_ARCH_USE_SIGACTION)
+#elif defined(__sparc__)
#define GET_CONTEXT \
- void *ctx = context;
+ void *ctx = sigctx;
#else
#define GET_CONTEXT \
void **_p = (void **)&_dummy; \
struct sigcontext *ctx = (struct sigcontext *)++_p;
#endif
#endif
+#endif
#ifdef MONO_ARCH_USE_SIGACTION
#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
+#elif defined(__sparc__)
+#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
#else
#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
#endif
mono_arch_handle_exception (ctx, exc, FALSE);
}
+#ifndef PLATFORM_WIN32
+
static void
SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
{
mono_print_thread_dump (ctx);
}
+static void
+SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
+{
+ gboolean enabled = mono_trace_is_enabled ();
+
+ mono_trace_enable (!enabled);
+}
+
+#endif
+
static void
SIG_HANDLER_SIGNATURE (sigint_signal_handler)
{
mono_arch_handle_exception (ctx, exc, FALSE);
}
+#ifdef PLATFORM_MACOSX
+
+/*
+ * This code disables the CrashReporter of MacOS X by installing
+ * a dummy Mach exception handler.
+ */
+
+/*
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
+ */
+extern
+boolean_t
+exc_server (mach_msg_header_t *request_msg,
+ mach_msg_header_t *reply_msg);
+
+/*
+ * The exception message
+ */
+typedef struct {
+ mach_msg_base_t msg; /* common mach message header */
+ char payload [1024]; /* opaque */
+} mach_exception_msg_t;
+
+/* The exception port */
+static mach_port_t mach_exception_port = VM_MAP_NULL;
+
+/*
+ * Implicitly called by exc_server. Must be public.
+ *
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
+ */
+kern_return_t
+catch_exception_raise (
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t code_count)
+{
+ /* consume the exception */
+ return KERN_FAILURE;
+}
+
+/*
+ * Exception thread handler.
+ */
+static
+void *
+mach_exception_thread (void *arg)
+{
+ for (;;) {
+ mach_exception_msg_t request;
+ mach_exception_msg_t reply;
+ mach_msg_return_t result;
+
+ /* receive from "mach_exception_port" */
+ result = mach_msg (&request.msg.header,
+ MACH_RCV_MSG | MACH_RCV_LARGE,
+ 0,
+ sizeof (request),
+ mach_exception_port,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ g_assert (result == MACH_MSG_SUCCESS);
+
+ /* dispatch to catch_exception_raise () */
+ exc_server (&request.msg.header, &reply.msg.header);
+
+ /* send back to sender */
+ result = mach_msg (&reply.msg.header,
+ MACH_SEND_MSG,
+ reply.msg.header.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ g_assert (result == MACH_MSG_SUCCESS);
+ }
+ return NULL;
+}
+
static void
-SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
+macosx_register_exception_handler ()
{
- gboolean enabled = mono_trace_is_enabled ();
+ mach_port_t task;
+ pthread_attr_t attr;
+ pthread_t thread;
- mono_trace_enable (!enabled);
+ if (mach_exception_port != VM_MAP_NULL)
+ return;
+
+ task = mach_task_self ();
+
+ /* create the "mach_exception_port" with send & receive rights */
+ g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
+ &mach_exception_port) == KERN_SUCCESS);
+ g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
+ MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
+
+ /* create the exception handler thread */
+ g_assert (!pthread_attr_init (&attr));
+ g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
+ g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
+ pthread_attr_destroy (&attr);
+
+ /*
+ * register "mach_exception_port" as a receiver for the
+ * EXC_BAD_ACCESS exception
+ *
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
+ */
+ g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
+ mach_exception_port,
+ EXCEPTION_DEFAULT,
+ MACHINE_THREAD_STATE) == KERN_SUCCESS);
}
+#endif
#ifndef PLATFORM_WIN32
static void
#else /* !PLATFORM_WIN32 */
+
+#ifdef PLATFORM_MACOSX
+ macosx_register_exception_handler ();
+#endif
+
if (debug_options.handle_sigint)
add_signal_handler (SIGINT, sigint_signal_handler);
}
#endif
+#ifdef PLATFORM_WIN32
+static HANDLE win32_main_thread;
+static MMRESULT win32_timer;
+
+static void CALLBACK
+win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+ CONTEXT context;
+
+ context.ContextFlags = CONTEXT_CONTROL;
+ if (GetThreadContext (win32_main_thread, &context)) {
+#ifdef _WIN64
+ mono_profiler_stat_hit ((guchar *) context.Rip, &context);
+#else
+ mono_profiler_stat_hit ((guchar *) context.Eip, &context);
+#endif
+ }
+}
+#endif
+
static void
setup_stat_profiler (void)
{
return;
inited = 1;
add_signal_handler (SIGPROF, sigprof_signal_handler);
+#elif defined (PLATFORM_WIN32)
+ static int inited = 0;
+ TIMECAPS timecaps;
+
+ if (inited)
+ return;
+
+ inited = 1;
+ if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
+ return;
+
+ if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
+ return;
+
+ if (timeBeginPeriod (1) != TIMERR_NOERROR)
+ return;
+
+ if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
+ timeEndPeriod (1);
+ return;
+ }
#endif
}
}
MonoDomain *
-mini_init (const char *filename)
+mini_init (const char *filename, const char *runtime_version)
{
MonoDomain *domain;
mono_aot_set_make_unreadable (TRUE);
}
- domain = mono_init_from_assembly (filename, filename);
+ if (runtime_version)
+ domain = mono_init_version (filename, runtime_version);
+ else
+ domain = mono_init_from_assembly (filename, filename);
mono_icall_init ();
mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
+#endif
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
#endif
mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
#endif
+#ifdef MONO_ARCH_SOFT_FLOAT
+ mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
+ mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
+ mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
+ mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
+ mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
+ mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
+
+ mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
+ mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
+ mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
+ mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
+ mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
+ mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
+ mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
+ mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
+ mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
+ mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
+
+ mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
+ mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
+ mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
+ mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
+ mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
+
+ register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
+ register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
+ register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
+#endif
+
#if SIZEOF_VOID_P == 4
mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
#endif
g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
-
+ g_print ("Locals stack size: %ld\n", mono_jit_stats.locals_stack_size);
+
g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
g_print ("Used classes: %ld\n", mono_stats.used_class_count);